From 54262da9aa930df8d7b2e11892815c1ef018f33a Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 18 Jan 2024 10:02:38 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 915880 - Add onclose event handlers in the MozInterAppMessagePort. r=ehsan,fabrice (5c57a3d571) - Bug 1227206 - Location.assign and Location.replace should use USVStrings instead DOMStrings, r=bz (5069baa300) - Bug 912342 - Add MediaStreamTrack.applyConstraints webidl. r=smaug (b43b0e0533) - Bug 1160123 - Add support for LTE/WCDMA only network selection. r=hsinyi (82f0d18d75) - Bug 993311 - Convert Network Stats API to WebIDL. r=bzbarsky. (4815cd4b57) - Bug 993311 - Followup to fix b2g builds r=khuey (1294ac6d8e) - Bug 1224944 - Improve the comments in NavigatorLanguage interface, r=bz (767104d09f) - Bug 1233702 - Remove dom.permissions.enabled pref. r=baku (fc6a65d714) - Bug 1224892 - Caching oscpu' and buildID' like other attributes related to User Agent. r=smaug (2e815d46af) - Bug 1238205 - Mark Navigator.serviceWorker as SameObject; r=baku (66be34314b) - Bug 1167541 - Implemented SpeechSynthesisEvent::utterance. r=smaug (eb2239ec4f) - Bug 1167542 - Implement SpeechSynthesisErrorEvent. r=smaug (bd01bdb144) - Bug 1238680 - Make dictionary arguments where a dictionary has a required member non-optional; r=bzbarsky (26a34e5279) - fix tests (0198243cef) - Bug 1192492 - Support masking of passwords in XUL tree columns. r=Enn,smaug (8594fafcb7) - Bug 1170452 - Remove constants for texture swizzle and prim restart. r=smaug (16e00c7565) - Bug 1237783 - Make sure we correctly turn off appcache. r=ehsan (49f25a95ee) - Bug 1218152 - Make Window.caches and WorkerGlobalScope.caches SameObject; r=bzbarsky (adf893fdb5) - Bug 1137398 - disallow creating nested workers from ServiceWorker. r=baku (d720f362eb) - Bug 931243 - Remove the XMLHttpRequest APIs from ServiceWorkerGlobalScope; r=bzbarsky (52110da15d) - Bug 1238576 - disable mozApps API on desktop/Android; r=ehsan,ochameau,bz,mcmanus,jmaher,marco (79143c24b3) - Bug 1233234 - part 1 - use UniquePtr instead of nsAutoArrayPtr in openPrefFile; r=njn (9b2d083dd0) - Bug 1233234 - part 2 - use UniquePtr instead of nsAutoArrayPtr in pref_savePrefs; r=njn (4946a07998) - Bug 1244982 - Fix minor double-reporting of memory in prefs code. r=erahm. (872c2c9b32) - Bug 1233234 - part 3 - clean up UniquePtr usage in WritePrefFile; r=njn (1a37c3dca1) - Bug 1241549 - Annotate intentional switch fallthrough in hal/linux/UPowerClient.cpp. r=gsvelto (7072ad9642) - Bug 1167581 - Inconsistent pre-zeroing of ioctl buffers in gecko/hal/gonk/GonkFMRadio.cpp. r=mwu. (9e529cb0ac) - Bug 1194721: Support Gonk sensors daemon, r=gsvelto (f2f47914ed) - Bug 1137151: Marked destructors of ref-counted GonkHAL classes as protected, r=dhylands (7fb6a4792f) - Bug 1116368 - Implementation of battery charging remaining time. r=dhylands (9b04442b6a) - Bug 1163245 - [Battery][Gonk] Implementation of battery discharging remaining time. r=dhylands (96fb254ae9) - Bug 1125084 - Uninitialised value use in mozilla::hal_impl::SetScreenBrightness(double). r=dhylands. (41f37994e5) - Bug 1123628 - mozilla::hal_impl::PriorityClass::~PriorityClass() closes not-open files. r=dhylands. (4ae357d587) - Bug 1208418: Shut down UeventPoller on XPCOM shutdown to fix the crash when the chrome process exits. r=dhylands (5b1192f310) - Bug 1194721: Add registry interface and module for Gonk sensors, r=gsvelto (3936dcf96a) - Bug 1194721: Add poll interface and module for Gonk sensors, r=gsvelto (101c0a2cf2) - Bug 1194721: Add interface for Gonk sensors daemon, r=gsvelto (5a8ea8e2ad) - Bug 1150232 - Stop gap solution until we can integrate the graphics docs. r=mstange (5a77195fb2) - Bug 1235740 - Remove warning for missing Oculus VR Library from terminal output, as it is spammy and not necessary r=dholbert (628eaddc43) - Bug 1235803 - Remove erroneous assertion r=dholbert (68287ff5ca) - Bug 1222569 - remove unused variable in gfxDWriteFonts.cpp; r=Bas (c940b5f1e4) - Bug 1212731 p1 - move GetSampleLangForGroup into base class. r=m_kato (a3cc3da7a7) - Bug 1212731 p2 - add system font cascade to fontlist for -apple-system generic. r=m_kato (18056700de) - Bug 1212731 p3 - reftest for system generic handling. r=m_kato (9aa64348b3) - bit of Bug 1212731 p2 (0a0be8302c) - Bug 1244017 - remove system font cascade for OSX. r=m_kato (742097b19e) - Bug 1251995 part 1 - Add helper functions to simplify code. r=jfkthame (f533af33bb) - Bug 1240739 - Support opacity when rendering color fonts (e.g. emoji). r=jdaggett (27c87cb70b) - Bug 1251995 part 2 - Add gfxTextRun::Range to replace parameter pairs like (offset, length) and (start, end). r=jfkthame (e87c55be94) - Bug 1251995 part 3 - Use struct to pass params for gfxTextRun::Draw. r=jfkthame (fbe0cc3f7d) - Bug 1251995 part 4 - Use struct to pass params for nsTextFrame::DrawText* functions. r=jfkthame (7d78727d65) - Remove an extra assignment from gfxSparseBitSet::TestRange, no bug (065a8c74e1) - Bug 1239603 - don't reject format 12 cmap with odd encoding. r=jfkthame (448ec8ab5e) - Bug 724538 - When ICU is available in the build, replace most of nsCharProps2 fields with ICU property accessors. r=emk (3578679d8e) - Bug 1228540 - pt 2 - Remove our HBGetGlyphHOrigin callback, as the default behavior is sufficient. r=jdaggett (9af85e376d) - Bug 1235407 - Part 1: Add telemetry probe to record forced resets. r=milan (fd1fee75a4) - Bug 1235407 - Part 2: Add ability to force device resets through gfxWindowsPlatform. r=milan (18479d140c) - TenFourFox backport of font stuff in attempt of 10.5 support (f9a55f3978) - Bug 1249212 part 2 - Fix infinity handling in StickyTimeDurationValueCalculator::Multiply; r=froydnj (e696303246) - Bug 1184695 - Fix some indentation in nsHashPropertyBag. r=poiru (6c1bed1ecd) - Bug 1182926 - Fix "observer-service-suspect" bustage. r=poiru. (25964b3802) - Bug 1234542 - Don't use fallible Add in SetStringProperty. r=froydnj (2c9b93264a) - Bug 1233566: Drop unnecessary newline character from NS_WARNING in nsPersistentProperties. r=froydnj (4ed1b9680d) - Bug 1193564 - Check result of Read32 in nsSupportsArray::Read. r=erahm (b6983798f9) - Bug 996105 - Added tests for registry access. Fixed wrong condition in ReadStringValue code. r=bsmedberxg (5945256572) --- dom/activities/tests/mochi/mochitest.ini | 2 +- dom/apps/InterAppCommService.jsm | 10 +- dom/apps/InterAppMessagePort.js | 53 +- dom/apps/moz.build | 5 +- dom/apps/tests/b2g_chrome.ini | 6 + dom/apps/tests/chrome.ini | 2 +- dom/apps/tests/file_hosted_certified.webapp | 2 +- dom/apps/tests/iac/README.txt | 3 + dom/apps/tests/iac/makezips.sh | 9 + dom/apps/tests/iac/publisher/index.html | 9 + dom/apps/tests/iac/publisher/manifest.webapp | 5 + dom/apps/tests/iac/publisher/publisher.list | 3 + dom/apps/tests/iac/publisher/publisher.zip | Bin 0 -> 1095 bytes dom/apps/tests/iac/publisher/test.js | 46 ++ dom/apps/tests/iac/publisher/update.webapp | 6 + .../iac/publisher/update.webapp^headers^ | 1 + dom/apps/tests/iac/subscriber/index.html | 9 + dom/apps/tests/iac/subscriber/manifest.webapp | 11 + dom/apps/tests/iac/subscriber/subscriber.list | 3 + dom/apps/tests/iac/subscriber/subscriber.zip | Bin 0 -> 846 bytes dom/apps/tests/iac/subscriber/test.js | 9 + dom/apps/tests/iac/subscriber/update.webapp | 12 + .../iac/subscriber/update.webapp^headers^ | 1 + dom/apps/tests/mochitest.ini | 5 +- dom/apps/tests/test_iac.html | 237 ++++++ dom/apps/tests/test_packaged_app_install.html | 2 +- .../test/test_navigator_resolve_identity.html | 7 - .../test_navigator_resolve_identity_xrays.xul | 5 - dom/bindings/test/test_bug707564-chrome.html | 8 +- dom/bindings/test/test_bug707564.html | 8 +- dom/broadcastchannel/tests/mochitest.ini | 4 +- dom/browser-element/mochitest/chrome.ini | 2 +- .../mochitest/mochitest-oop.ini | 5 +- dom/browser-element/mochitest/mochitest.ini | 8 +- dom/cache/test/mochitest/mochitest.ini | 2 +- dom/canvas/CanvasRenderingContext2D.cpp | 21 +- dom/datastore/tests/mochitest.ini | 2 +- dom/events/ContentEventHandler.cpp | 7 +- .../test/test_all_synthetic_events.html | 7 + dom/indexedDB/test/mochitest.ini | 18 +- dom/media/test/crashtests/crashtests.list | 2 +- .../synth/SpeechSynthesisUtterance.cpp | 1 + .../webspeech/synth/test/file_setup.html | 1 + dom/messages/test/chrome.ini | 4 +- .../test_mobile_preferred_network_type.js | 3 + dom/network/NetworkStatsManager.js | 110 +-- dom/network/NetworkStatsManager.manifest | 1 - dom/network/interfaces/moz.build | 1 - .../tests/test_networkstats_alarms.html | 22 +- .../tests/test_networkstats_basics.html | 4 +- .../tests/test_networkstats_disabled.html | 6 +- .../test_networkstats_enabled_no_perm.html | 22 +- .../tests/test_networkstats_enabled_perm.html | 4 +- .../tests/unit_stats/test_networkstats_db.js | 4 +- .../unit_stats/test_networkstats_service.js | 4 +- dom/permission/tests/mochitest.ini | 1 + .../tests/test_networkstats-manage.html | 2 +- dom/requestsync/tests/mochitest.ini | 2 +- dom/security/test/csp/mochitest.ini | 1 + dom/system/gonk/ril_consts.js | 4 +- dom/tests/mochitest/fetch/mochitest.ini | 23 +- .../mochitest/general/test_interfaces.html | 14 +- dom/tests/mochitest/localstorage/chrome.ini | 2 + .../localstorage/test_app_uninstall.html | 2 +- .../mochitest/notification/mochitest.ini | 2 +- dom/webidl/InterAppMessagePort.webidl | 1 + dom/webidl/Location.webidl | 4 +- dom/webidl/MediaStreamTrack.webidl | 30 +- dom/webidl/MozMobileConnection.webidl | 4 +- dom/webidl/MozNetworkStats.webidl | 6 +- .../MozNetworkStatsManager.webidl} | 44 +- dom/webidl/Navigator.webidl | 14 +- dom/webidl/NotificationEvent.webidl | 2 +- dom/webidl/PermissionStatus.webidl | 3 +- dom/webidl/Permissions.webidl | 3 +- dom/webidl/SpeechSynthesisErrorEvent.webidl | 36 + dom/webidl/SpeechSynthesisEvent.webidl | 4 +- dom/webidl/TreeColumn.webidl | 1 + dom/webidl/WebGL2RenderingContext.webidl | 5 - dom/webidl/Window.webidl | 4 +- dom/webidl/Worker.webidl | 4 +- dom/webidl/WorkerGlobalScope.webidl | 2 +- dom/webidl/XMLHttpRequest.webidl | 2 +- dom/webidl/XMLHttpRequestEventTarget.webidl | 2 +- dom/webidl/XMLHttpRequestUpload.webidl | 2 +- dom/webidl/moz.build | 15 +- .../test_serviceworker_interfaces.js | 6 - extensions/cookie/test/chrome.ini | 3 + .../test/test_app_uninstall_cookies.html | 3 +- .../test/test_app_uninstall_permissions.html | 16 +- gfx/docs/index.rst | 9 + gfx/moz.build | 1 + gfx/src/nsFontMetrics.cpp | 43 +- gfx/src/nsFontMetrics.h | 1 + gfx/thebes/gfxDWriteFonts.cpp | 2 - gfx/thebes/gfxFcPlatformFontList.cpp | 126 --- gfx/thebes/gfxFcPlatformFontList.h | 6 - gfx/thebes/gfxFont.cpp | 9 +- gfx/thebes/gfxFontUtils.cpp | 34 +- gfx/thebes/gfxFontUtils.h | 25 +- gfx/thebes/gfxFontconfigFonts.cpp | 24 +- gfx/thebes/gfxHarfBuzzShaper.cpp | 14 - gfx/thebes/gfxHarfBuzzShaper.h | 5 - gfx/thebes/gfxMacPlatformFontList.h | 45 +- gfx/thebes/gfxMacPlatformFontList.mm | 718 +++++++++++++++++- gfx/thebes/gfxPlatform.h | 6 + gfx/thebes/gfxPlatformFontList.cpp | 131 ++++ gfx/thebes/gfxPlatformFontList.h | 8 + gfx/thebes/gfxPlatformMac.cpp | 27 + gfx/thebes/gfxPlatformMac.h | 31 + gfx/thebes/gfxScriptItemizer.cpp | 12 +- gfx/thebes/gfxTextRun.cpp | 423 ++++++----- gfx/thebes/gfxTextRun.h | 149 ++-- gfx/thebes/gfxWindowsPlatform.cpp | 9 + gfx/thebes/gfxWindowsPlatform.h | 5 + gfx/vr/gfxVROculus.cpp | 1 - gfx/vr/gfxVROculus050.cpp | 1 - gfx/vr/ipc/VRManagerParent.cpp | 1 - hal/gonk/GonkFMRadio.cpp | 6 +- hal/gonk/GonkHal.cpp | 121 ++- hal/gonk/GonkSensor.cpp | 533 ++++++++++++- hal/gonk/GonkSensorsInterface.cpp | 494 ++++++++++++ hal/gonk/GonkSensorsInterface.h | 190 +++++ hal/gonk/GonkSensorsPollInterface.cpp | 430 +++++++++++ hal/gonk/GonkSensorsPollInterface.h | 343 +++++++++ hal/gonk/GonkSensorsRegistryInterface.cpp | 212 ++++++ hal/gonk/GonkSensorsRegistryInterface.h | 185 +++++ hal/gonk/GonkSwitch.cpp | 8 +- hal/gonk/UeventPoller.cpp | 98 ++- hal/linux/UPowerClient.cpp | 2 + hal/moz.build | 3 + .../tools/genUnicodePropertyData.pl | 315 +++----- intl/unicharutil/util/nsBidiUtils.h | 9 +- intl/unicharutil/util/nsUnicodeProperties.cpp | 106 ++- intl/unicharutil/util/nsUnicodeProperties.h | 22 +- js/xpconnect/tests/chrome/test_bug853283.xul | 2 +- layout/generic/MathMLTextRunFactory.cpp | 9 +- layout/generic/TextOverflow.cpp | 6 +- layout/generic/nsTextFrame.cpp | 593 +++++++-------- layout/generic/nsTextFrame.h | 92 +-- layout/generic/nsTextRunTransformations.cpp | 12 +- layout/generic/nsTextRunTransformations.h | 3 +- layout/inspector/nsFontFaceList.cpp | 3 +- layout/mathml/nsMathMLChar.cpp | 29 +- layout/mathml/nsMathMLChar.h | 3 +- layout/reftests/font-matching/reftest.list | 11 + .../system-generic-fallback-1-ref.html | 39 + .../system-generic-fallback-1.html | 39 + .../system-generic-fallback-2-ref.html | 38 + .../system-generic-fallback-2.html | 38 + .../system-generic-fallback-3-ref.html | 38 + .../system-generic-fallback-3.html | 38 + .../system-generic-fallback-4-ref.html | 38 + .../system-generic-fallback-4.html | 38 + .../system-generic-fallback-ja.html | 33 + .../system-generic-fallback-ko.html | 33 + .../system-generic-fallback-zh-cn.html | 33 + .../system-generic-fallback-zh-tw.html | 33 + layout/svg/SVGTextFrame.cpp | 135 ++-- layout/svg/SVGTextFrame.h | 2 + layout/xul/nsXULTooltipListener.cpp | 7 +- layout/xul/tree/nsITreeColumns.idl | 1 + layout/xul/tree/nsTreeBodyFrame.cpp | 7 + layout/xul/tree/nsTreeColumns.cpp | 4 +- modules/libpref/Preferences.cpp | 26 +- modules/libpref/init/all.js | 13 +- modules/libpref/prefapi.cpp | 11 +- modules/libpref/prefapi_private_data.h | 5 +- netwerk/test/mochitests/mochitest.ini | 1 + .../tests/Harness_sanity/mochitest.ini | 4 +- .../web-platform/mozilla/meta/MANIFEST.json | 14 +- .../sync-xhr-doesnt-deadlock.https.html.ini | 9 - .../sync-xhr-doesnt-deadlock-iframe.html | 12 - .../resources/sync-xhr-doesnt-deadlock.data | 1 - .../resources/sync-xhr-doesnt-deadlock.js | 5 - .../service-worker/resources/xhr.js | 6 + .../sync-xhr-doesnt-deadlock.https.html | 23 - .../service-worker/xhr.https.html | 34 + toolkit/components/telemetry/Histograms.json | 7 + toolkit/content/widgets/tree.xml | 6 +- toolkit/devtools/apps/tests/mochitest.ini | 3 +- .../prefetch/nsOfflineCacheUpdateService.cpp | 13 + xpcom/ds/StickyTimeDuration.h | 4 +- xpcom/ds/nsHashPropertyBag.cpp | 18 +- xpcom/ds/nsObserverService.cpp | 32 +- xpcom/ds/nsPersistentProperties.cpp | 4 +- xpcom/ds/nsSupportsArray.cpp | 3 + xpcom/ds/nsWindowsRegKey.cpp | 2 +- xpcom/tests/unit/test_windows_registry.js | 205 +++++ xpcom/tests/unit/xpcshell.ini | 2 + 190 files changed, 6090 insertions(+), 1686 deletions(-) create mode 100644 dom/apps/tests/b2g_chrome.ini create mode 100644 dom/apps/tests/iac/README.txt create mode 100644 dom/apps/tests/iac/makezips.sh create mode 100644 dom/apps/tests/iac/publisher/index.html create mode 100644 dom/apps/tests/iac/publisher/manifest.webapp create mode 100644 dom/apps/tests/iac/publisher/publisher.list create mode 100644 dom/apps/tests/iac/publisher/publisher.zip create mode 100644 dom/apps/tests/iac/publisher/test.js create mode 100644 dom/apps/tests/iac/publisher/update.webapp create mode 100644 dom/apps/tests/iac/publisher/update.webapp^headers^ create mode 100644 dom/apps/tests/iac/subscriber/index.html create mode 100644 dom/apps/tests/iac/subscriber/manifest.webapp create mode 100644 dom/apps/tests/iac/subscriber/subscriber.list create mode 100644 dom/apps/tests/iac/subscriber/subscriber.zip create mode 100644 dom/apps/tests/iac/subscriber/test.js create mode 100644 dom/apps/tests/iac/subscriber/update.webapp create mode 100644 dom/apps/tests/iac/subscriber/update.webapp^headers^ create mode 100644 dom/apps/tests/test_iac.html rename dom/{network/interfaces/nsIDOMNetworkStatsManager.idl => webidl/MozNetworkStatsManager.webidl} (65%) create mode 100644 dom/webidl/SpeechSynthesisErrorEvent.webidl create mode 100644 gfx/docs/index.rst create mode 100644 hal/gonk/GonkSensorsInterface.cpp create mode 100644 hal/gonk/GonkSensorsInterface.h create mode 100644 hal/gonk/GonkSensorsPollInterface.cpp create mode 100644 hal/gonk/GonkSensorsPollInterface.h create mode 100644 hal/gonk/GonkSensorsRegistryInterface.cpp create mode 100644 hal/gonk/GonkSensorsRegistryInterface.h create mode 100644 layout/reftests/font-matching/system-generic-fallback-1-ref.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-1.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-2-ref.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-2.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-3-ref.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-3.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-4-ref.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-4.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-ja.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-ko.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-zh-cn.html create mode 100644 layout/reftests/font-matching/system-generic-fallback-zh-tw.html delete mode 100644 testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini delete mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html delete mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data delete mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js create mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js delete mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html create mode 100644 testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html create mode 100644 xpcom/tests/unit/test_windows_registry.js diff --git a/dom/activities/tests/mochi/mochitest.ini b/dom/activities/tests/mochi/mochitest.ini index 23925f10b9..00bdf46069 100644 --- a/dom/activities/tests/mochi/mochitest.ini +++ b/dom/activities/tests/mochi/mochitest.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = e10s +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') support-files = system.webapp system.webapp^headers^ diff --git a/dom/apps/InterAppCommService.jsm b/dom/apps/InterAppCommService.jsm index 7a9dc0e679..535069334f 100644 --- a/dom/apps/InterAppCommService.jsm +++ b/dom/apps/InterAppCommService.jsm @@ -883,6 +883,14 @@ this.InterAppCommService = { if (DEBUG) { debug("Unregistering message port for " + manifestURL); } + + let receiver = identity.isPublisher ? identity.pair.subscriber + : identity.pair.publisher; + receiver.target.sendAsyncMessage("InterAppMessagePort:OnClose", + { manifestURL: receiver.manifestURL, + pageURL: receiver.pageURL, + messagePortID: messagePortID }); + delete this._messagePortPairs[messagePortID]; }, @@ -901,7 +909,7 @@ this.InterAppCommService = { messagePortIDs.push(messagePortID); // Send a shutdown message to the part of the pair that is still alive. let actor = pair.publisher.target === aTarget ? pair.subscriber - : pair.publisher; + : pair.publisher; actor.target.sendAsyncMessage("InterAppMessagePort:Shutdown", { manifestURL: actor.manifestURL, pageURL: actor.pageURL, diff --git a/dom/apps/InterAppMessagePort.js b/dom/apps/InterAppMessagePort.js index 7d3ec9ba7a..4a9b3a9794 100644 --- a/dom/apps/InterAppMessagePort.js +++ b/dom/apps/InterAppMessagePort.js @@ -30,7 +30,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "appsService", "@mozilla.org/AppsService;1", "nsIAppsService"); -const kMessages = ["InterAppMessagePort:OnMessage", +const kMessages = ["InterAppMessagePort:OnClose", + "InterAppMessagePort:OnMessage", "InterAppMessagePort:Shutdown"]; function InterAppMessagePort() { @@ -66,6 +67,7 @@ InterAppMessagePort.prototype = { this._started = false; this._closed = false; this._messageQueue = []; + this._deferredClose = false; }, // WebIDL implementation for constructor. @@ -131,6 +133,10 @@ InterAppMessagePort.prototype = { let message = this._messageQueue.shift(); this._dispatchMessage(message); } + + if (this._deferredClose) { + this._dispatchClose(); + } }, close: function() { @@ -143,6 +149,7 @@ InterAppMessagePort.prototype = { } this._closed = true; + this._deferredClose = false; this._messageQueue.length = 0; // When this method called on a local port that is entangled with another @@ -152,6 +159,8 @@ InterAppMessagePort.prototype = { manifestURL: this._manifestURL }); this.removeMessageListeners(kMessages); + + this._dispatchClose(); }, get onmessage() { @@ -176,6 +185,16 @@ InterAppMessagePort.prototype = { this.start(); }, + get onclose() { + if (DEBUG) debug("Getting onclose handler."); + return this.__DOM_IMPL__.getEventHandler("onclose"); + }, + + set onclose(aHandler) { + if (DEBUG) debug("Setting onclose handler."); + this.__DOM_IMPL__.setEventHandler("onclose", aHandler); + }, + _dispatchMessage: function _dispatchMessage(aMessage) { let wrappedMessage = Cu.cloneInto(aMessage, this._window); if (DEBUG) { @@ -189,6 +208,15 @@ InterAppMessagePort.prototype = { this.__DOM_IMPL__.dispatchEvent(event); }, + _dispatchClose() { + if (DEBUG) debug("_dispatchClose"); + let event = new this._window.Event("close", { + bubbles: true, + cancelable: true + }); + this.__DOM_IMPL__.dispatchEvent(event); + }, + receiveMessage: function(aMessage) { if (DEBUG) debug("receiveMessage: name: " + aMessage.name); @@ -217,11 +245,32 @@ InterAppMessagePort.prototype = { this._dispatchMessage(message.message); break; + case "InterAppMessagePort:OnClose": + if (this._closed) { + if (DEBUG) debug("close() has been called. Drop the message."); + return; + } + + // It is possible that one side of the port posts messages and calls + // close() before calling start() or setting the onmessage handler. In + // that case we need to queue the messages and defer the onclose event + // until the messages are delivered to the other side of the port. + if (!this._started) { + if (DEBUG) debug("Not yet called start(). Defer close notification."); + this._deferredClose = true; + return; + } + + this._dispatchClose(); + break; + case "InterAppMessagePort:Shutdown": this.close(); break; + default: - if (DEBUG) debug("Error! Shouldn't fall into this case."); + dump("WARNING - Invalid InterAppMessagePort message type " + + aMessage.name + "\n"); break; } } diff --git a/dom/apps/moz.build b/dom/apps/moz.build index 419ad9a45f..866dc47222 100644 --- a/dom/apps/moz.build +++ b/dom/apps/moz.build @@ -8,7 +8,10 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] -MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini'] +MOCHITEST_CHROME_MANIFESTS += [ + 'tests/b2g_chrome.ini', + 'tests/chrome.ini' +] EXPORTS.mozilla.dom += [ 'InterAppComm.h', diff --git a/dom/apps/tests/b2g_chrome.ini b/dom/apps/tests/b2g_chrome.ini new file mode 100644 index 0000000000..bc13bf326b --- /dev/null +++ b/dom/apps/tests/b2g_chrome.ini @@ -0,0 +1,6 @@ +[DEFAULT] +skip-if = buildapp != 'b2g' +support-files = + iac/* + +[test_iac.html] diff --git a/dom/apps/tests/chrome.ini b/dom/apps/tests/chrome.ini index 3348cb6db4..e908d99539 100644 --- a/dom/apps/tests/chrome.ini +++ b/dom/apps/tests/chrome.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = buildapp == 'b2g' || os == 'android' +skip-if = buildapp != 'mulet' support-files = asmjs/* common.js diff --git a/dom/apps/tests/file_hosted_certified.webapp b/dom/apps/tests/file_hosted_certified.webapp index c027b37efb..d1b940f889 100644 --- a/dom/apps/tests/file_hosted_certified.webapp +++ b/dom/apps/tests/file_hosted_certified.webapp @@ -1,6 +1,6 @@ { "name": "Certified hosted app", - "description": "An app that can't only be installed in dev mode.", + "description": "An app that can only be installed in dev mode.", "launch_path": "/tests/dom/apps/tests/file_app.sjs?apptype=hosted", "type": "certified" } diff --git a/dom/apps/tests/iac/README.txt b/dom/apps/tests/iac/README.txt new file mode 100644 index 0000000000..326536bf28 --- /dev/null +++ b/dom/apps/tests/iac/README.txt @@ -0,0 +1,3 @@ +subscriber.list and publisher.zip contain the lists of files that are part of each app. + +To update the packages of both apps when changing one of those files listed on *.list, run makezips.sh. diff --git a/dom/apps/tests/iac/makezips.sh b/dom/apps/tests/iac/makezips.sh new file mode 100644 index 0000000000..f94d4a9e01 --- /dev/null +++ b/dom/apps/tests/iac/makezips.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +rm publisher/publisher.zip +rm subscriber/subscriber.zip +cd publisher +zip publisher.zip `cat publisher.list` +cd ../subscriber +zip subscriber.zip `cat subscriber.list` +cd .. diff --git a/dom/apps/tests/iac/publisher/index.html b/dom/apps/tests/iac/publisher/index.html new file mode 100644 index 0000000000..c584807b26 --- /dev/null +++ b/dom/apps/tests/iac/publisher/index.html @@ -0,0 +1,9 @@ + + + + Publisher app for IAC API + + + + + diff --git a/dom/apps/tests/iac/publisher/manifest.webapp b/dom/apps/tests/iac/publisher/manifest.webapp new file mode 100644 index 0000000000..cc9343f220 --- /dev/null +++ b/dom/apps/tests/iac/publisher/manifest.webapp @@ -0,0 +1,5 @@ +{ + "name": "IAC publisher app", + "launch_path": "/index.html", + "type": "certified" +} diff --git a/dom/apps/tests/iac/publisher/publisher.list b/dom/apps/tests/iac/publisher/publisher.list new file mode 100644 index 0000000000..d94aad31cc --- /dev/null +++ b/dom/apps/tests/iac/publisher/publisher.list @@ -0,0 +1,3 @@ +manifest.webapp +index.html +test.js diff --git a/dom/apps/tests/iac/publisher/publisher.zip b/dom/apps/tests/iac/publisher/publisher.zip new file mode 100644 index 0000000000000000000000000000000000000000..dcfc3cdf7ff8e61ab0d58bad60bb8be8b69fccae GIT binary patch literal 1095 zcmWIWW@Zs#U|`^2IFnoHe&fWYDt{m^5{UU3WEgT2^D@&?i%ay%QZHy&58WUS9gToX zjGoU`raeao;fc2v_kmlJgS)+qE*k|0PuY>RlOX`^ zu7i1%?oJDQt@D9yng+yNKzC*4rKDEqWt8ORfSr`J9;=f!2bO#+=j-Gt2tA>3^6bXP zn;HYSxXdJ1c4{iHO^BQnIcaj1c)+YFlOyL$j9M}wB4ELUY4J-QynM0dfy9H%#r%N` zfiZJprbGrT3W%AKvpQr_RLr93p=(mo7xN3U&0fQAd`nH!eyNZWOCsaa1J{_5oSf2L z>8>0gZn_y5I8T@v7}$YME&&B&Rx#MUr-8u-!e~L58|>SE#eiq;_wX5UW}@ClW?ocS zTPD~px@JoUvlEA_Vks9v?QB&r9GhGe{HHm2-ZdbHM$|jd>pqoQpF2oj3KyO}&X- zd3SGcFO*c^?-F_QJs>SWk~?jo-r{xQJn25$Rz3=4ytShtIDbydp9UF=o92a{AH1jO z{9bZVXWk4;tFJ9Ks@)%d$%mHRRGS!4nkDUe?)168J74}*kY1vnkrn8vCbuO`HA2v4 zVd~NQ{(rm=_4g?l*ezw2XkYltuH7SOp0QV6ioq0xH`A=HDtdi&JAZZB)FsMMhJNNQ zMji1J`vNC~pZxxZ=cT{Y7GBxSdY;l!H8Ib2FvdJiXBV84E#vC_d|SWZmV{4}j$U}5 zU!U`)C{E4o%>U^VOs>_+{ke8`x5H&^f$)Q+9`16duO6viw { + ok(true, "Got self"); + let app = event.target.result; + app.connect("a-connection").then(ports => { + if (!ports || !ports.length) { + return ok(false, "No ports"); + } + ok(true, "Got port"); + _port = ports[0]; + _port.onmessage = onmessage; + _port.onclose = onclose; + _port.postMessage('something'); + }).catch(error => { + ok(false, "Unexpected " + error); + }); + }; +})(); diff --git a/dom/apps/tests/iac/publisher/update.webapp b/dom/apps/tests/iac/publisher/update.webapp new file mode 100644 index 0000000000..10d4776faa --- /dev/null +++ b/dom/apps/tests/iac/publisher/update.webapp @@ -0,0 +1,6 @@ +{ + "name": "IAC publisher app", + "launch_path": "/index.html", + "package_path": "publisher.zip", + "type": "certified" +} diff --git a/dom/apps/tests/iac/publisher/update.webapp^headers^ b/dom/apps/tests/iac/publisher/update.webapp^headers^ new file mode 100644 index 0000000000..a2367b11c7 --- /dev/null +++ b/dom/apps/tests/iac/publisher/update.webapp^headers^ @@ -0,0 +1 @@ +Content-Type: application/x-web-app-manifest+json diff --git a/dom/apps/tests/iac/subscriber/index.html b/dom/apps/tests/iac/subscriber/index.html new file mode 100644 index 0000000000..dcc352e18b --- /dev/null +++ b/dom/apps/tests/iac/subscriber/index.html @@ -0,0 +1,9 @@ + + + + Subscriber app for IAC API + + + + + diff --git a/dom/apps/tests/iac/subscriber/manifest.webapp b/dom/apps/tests/iac/subscriber/manifest.webapp new file mode 100644 index 0000000000..cd277b6496 --- /dev/null +++ b/dom/apps/tests/iac/subscriber/manifest.webapp @@ -0,0 +1,11 @@ +{ + "name": "IAC subscriber app", + "launch_path": "/index.html", + "type": "certified", + "connections": { + "a-connection": { + "description": "A connection", + "rules": {} + } + } +} diff --git a/dom/apps/tests/iac/subscriber/subscriber.list b/dom/apps/tests/iac/subscriber/subscriber.list new file mode 100644 index 0000000000..d94aad31cc --- /dev/null +++ b/dom/apps/tests/iac/subscriber/subscriber.list @@ -0,0 +1,3 @@ +manifest.webapp +index.html +test.js diff --git a/dom/apps/tests/iac/subscriber/subscriber.zip b/dom/apps/tests/iac/subscriber/subscriber.zip new file mode 100644 index 0000000000000000000000000000000000000000..024252362af2bbaa5c593b8683e20e446f56b3f3 GIT binary patch literal 846 zcmWIWW@Zs#U|`^2IFnZC&N){yz5&QP3dH;jG7Pzid6{Xc#U*;>sY!_i1)(9F49xip zL&Iclg@%<@a5FHnd}Cx_02|$oy14%c`RC zNg`h2{P(N3g)=Hdo>f_|@cuDx(mW+L>p+I5du5{Dg`}DAub-5;wL8^!{btY2w?BRP zRx7Wm@_Wk?^JA?u4Q{q3`(F1Fz54R}?y&1u?)}m~Ey%a^VK~>#!2O}SwnVxJ$_Kzb zqSjjJerI#HOCHb@(}9=^=#k94l++5njFQ|Oupg#h!|I34fh8Zy`8s(DLQiO%JiGDn zrp5p+E;GrMotg@46Cx)?PMVx09y2RsPRx{2QOc&c_8s1b1{D) zV<2x(NWh|im?=4{LncMVESes=CMA6_zaX3RT7Ki(YMS;-g_Kwl8J8aT#>{|laerH- zdwq^zbQjRIhk=+K=;9JkuxAy6ooja!t8-oZHgYi;^0a-obKU;U;T`KK&ZegBZoj^z zZI2gBzoKTP@%`Pk)kk$}etvr1uV57@w)}$q@{8P0>y}+-eZq34u4VD@=$0H`1s4t@ z!CAfM3hEiU<+lA=`(@UGcDLVB5rzI1*Ow^WSQq { + port = request.port; + port.onmessage = () => { + port.postMessage('response'); + port.close(); + }; +}); +alert('READY'); diff --git a/dom/apps/tests/iac/subscriber/update.webapp b/dom/apps/tests/iac/subscriber/update.webapp new file mode 100644 index 0000000000..a5833cd421 --- /dev/null +++ b/dom/apps/tests/iac/subscriber/update.webapp @@ -0,0 +1,12 @@ +{ + "name": "IAC subscriber app", + "launch_path": "/index.html", + "type": "certified", + "package_path": "subscriber.zip", + "connections": { + "a-connection": { + "description": "A connection", + "rules": {} + } + } +} diff --git a/dom/apps/tests/iac/subscriber/update.webapp^headers^ b/dom/apps/tests/iac/subscriber/update.webapp^headers^ new file mode 100644 index 0000000000..a2367b11c7 --- /dev/null +++ b/dom/apps/tests/iac/subscriber/update.webapp^headers^ @@ -0,0 +1 @@ +Content-Type: application/x-web-app-manifest+json diff --git a/dom/apps/tests/mochitest.ini b/dom/apps/tests/mochitest.ini index 8828904211..ae9fdf4364 100644 --- a/dom/apps/tests/mochitest.ini +++ b/dom/apps/tests/mochitest.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = e10s +skip-if = buildapp != 'b2g' && buildapp != 'mulet' support-files = addons/application.zip addons/update.webapp @@ -42,7 +42,8 @@ skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in moch skip-if = os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app [test_bug_795164.html] [test_bug_1168300.html] -skip-if = toolkit == "gonk" # see bug 1175784 +skip-if = toolkit == "gonk" || e10s # see bug 1175784 +[test_checkInstalled.html] [test_import_export.html] [test_install_dev_mode.html] [test_install_multiple_apps_origin.html] diff --git a/dom/apps/tests/test_iac.html b/dom/apps/tests/test_iac.html new file mode 100644 index 0000000000..45d02d2e22 --- /dev/null +++ b/dom/apps/tests/test_iac.html @@ -0,0 +1,237 @@ + + + + + Test for IAC API + + + + + + + +Mozilla Bug {915880} +

+ +
+
+
+
+ + diff --git a/dom/apps/tests/test_packaged_app_install.html b/dom/apps/tests/test_packaged_app_install.html index f03830a955..09ca0dbe16 100644 --- a/dom/apps/tests/test_packaged_app_install.html +++ b/dom/apps/tests/test_packaged_app_install.html @@ -155,7 +155,7 @@ var steps = [ PackagedTestHelper.gAppName); }, function() { - PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next); + PackagedTestHelper.setAppVersion(1, PackagedTestHelper.next); }, function() { // Test mini-manifest app name is different from the webapp manifest name. diff --git a/dom/base/test/test_navigator_resolve_identity.html b/dom/base/test/test_navigator_resolve_identity.html index 3bfeaf1ce2..882853525a 100644 --- a/dom/base/test/test_navigator_resolve_identity.html +++ b/dom/base/test/test_navigator_resolve_identity.html @@ -19,13 +19,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=985827 var y = navigator.mozContacts; is(x, y, "Should have gotten the same mozContacts object again"); - // Test Javascript-navigator-property objects - x = navigator.mozApps; - is(typeof x, "object", "Should have a mozApps object"); - delete navigator.mozApps; - y = navigator.mozApps; - is(x, y, "Should have gotten the same mozApps object again"); - diff --git a/dom/base/test/test_navigator_resolve_identity_xrays.xul b/dom/base/test/test_navigator_resolve_identity_xrays.xul index d2b733ac30..41ff4591b4 100644 --- a/dom/base/test/test_navigator_resolve_identity_xrays.xul +++ b/dom/base/test/test_navigator_resolve_identity_xrays.xul @@ -32,11 +32,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=985827 is(nav.mozContacts, nav.mozContacts, "Should have gotten the same mozContacts object again"); - // Test Javascript-navigator-property objects - is(typeof nav.mozApps, "object", "Should have a mozApps object"); - is(nav.mozApps, nav.mozApps, - "Should have gotten the same mozApps object again"); - SimpleTest.finish(); }); ]]> diff --git a/dom/bindings/test/test_bug707564-chrome.html b/dom/bindings/test/test_bug707564-chrome.html index cf5f8d78ff..7e3185a2a9 100644 --- a/dom/bindings/test/test_bug707564-chrome.html +++ b/dom/bindings/test/test_bug707564-chrome.html @@ -26,19 +26,19 @@ function test() is(nav.foopy, undefined, "We should have an Xray now"); is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object"); var props = Object.getOwnPropertyNames(nav); - isnot(props.indexOf("mozApps"), -1, - "Should enumerate a mozApps property on navigator xray"); + isnot(props.indexOf("mozContacts"), -1, + "Should enumerate a mozContacts property on navigator xray"); var nav = document.getElementById("t2").contentWindow.navigator; is(nav.foopy, undefined, "We should have an Xray now again"); is(nav.wrappedJSObject.foopy, 5, "We should have the right navigator object again"); var found = false; for (var name in nav) { - if (name == "mozApps") { + if (name == "mozContacts") { found = true; } } - ok(found, "Should enumerate a mozApps property on navigator xray via for...in"); + ok(found, "Should enumerate a mozContacts property on navigator xray via for...in"); SimpleTest.finish(); } diff --git a/dom/bindings/test/test_bug707564.html b/dom/bindings/test/test_bug707564.html index 8b0f9068b0..fb0929c633 100644 --- a/dom/bindings/test/test_bug707564.html +++ b/dom/bindings/test/test_bug707564.html @@ -15,17 +15,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=707564 addLoadEvent(function() { var props = Object.getOwnPropertyNames(frames[0].navigator); - isnot(props.indexOf("mozApps"), -1, - "Should enumerate a mozApps property on navigator"); + isnot(props.indexOf("mozContacts"), -1, + "Should enumerate a mozContacts property on navigator"); // Now enumerate a different navigator object var found = false; for (var name in frames[1].navigator) { - if (name == "mozApps") { + if (name == "mozContacts") { found = true; } } - ok(found, "Should enumerate a mozApps property on navigator via for...in"); + ok(found, "Should enumerate a mozContacts property on navigator via for...in"); SimpleTest.finish(); }); diff --git a/dom/broadcastchannel/tests/mochitest.ini b/dom/broadcastchannel/tests/mochitest.ini index f37dd65305..77419ee048 100644 --- a/dom/broadcastchannel/tests/mochitest.ini +++ b/dom/broadcastchannel/tests/mochitest.ini @@ -20,7 +20,7 @@ support-files = [test_broadcastchannel_worker.html] [test_broadcastchannel_worker_alive.html] [test_broadcastchannel_mozbrowser.html] -skip-if = e10s || buildapp == 'b2g' +skip-if = buildapp != 'mulet' [test_broadcastchannel_mozbrowser2.html] -skip-if = e10s || buildapp == 'b2g' +skip-if = buildapp != 'mulet' [test_bfcache.html] diff --git a/dom/browser-element/mochitest/chrome.ini b/dom/browser-element/mochitest/chrome.ini index 15e694812b..e45dc2123b 100644 --- a/dom/browser-element/mochitest/chrome.ini +++ b/dom/browser-element/mochitest/chrome.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) support-files = browserElement_NotifyChannel.js diff --git a/dom/browser-element/mochitest/mochitest-oop.ini b/dom/browser-element/mochitest/mochitest-oop.ini index f4e239656e..e543bb5196 100644 --- a/dom/browser-element/mochitest/mochitest-oop.ini +++ b/dom/browser-element/mochitest/mochitest-oop.ini @@ -22,9 +22,9 @@ skip-if = toolkit=='gonk' || (toolkit == 'gonk' && !debug) [test_browserElement_oop_Alert.html] [test_browserElement_oop_AlertInFrame.html] [test_browserElement_oop_AllowEmbedAppsInNestedOOIframe.html] -skip-if = toolkit=='gonk' +skip-if = toolkit == 'gonk' || buildapp != 'b2g' [test_browserElement_oop_AppFramePermission.html] -skip-if = (toolkit == 'gonk' && !debug) +skip-if = (toolkit == 'gonk' && !debug) || buildapp != 'b2g' [test_browserElement_oop_AppWindowNamespace.html] skip-if = (toolkit == 'gonk' && !debug) [test_browserElement_oop_Auth.html] @@ -40,6 +40,7 @@ skip-if = (toolkit == 'gonk' && !debug) [test_browserElement_oop_DOMRequestError.html] [test_browserElement_oop_DataURI.html] [test_browserElement_oop_DisallowEmbedAppsInOOP.html] +skip-if = buildapp != 'b2g' [test_browserElement_oop_DocumentFirstPaint.html] [test_browserElement_oop_Download.html] disabled = bug 1022281 diff --git a/dom/browser-element/mochitest/mochitest.ini b/dom/browser-element/mochitest/mochitest.ini index 2dc9cb8096..a69c4907ab 100644 --- a/dom/browser-element/mochitest/mochitest.ini +++ b/dom/browser-element/mochitest/mochitest.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s +skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || e10s support-files = ../../../browser/base/content/test/general/audio.ogg ../../../dom/media/test/short-video.ogv @@ -154,7 +154,7 @@ support-files = skip-if = buildapp == 'b2g' [test_browserElement_inproc_AlertInFrame.html] [test_browserElement_inproc_AppFramePermission.html] -skip-if = toolkit == 'android' || buildapp == 'b2g' +skip-if = toolkit == 'android' || buildapp != 'mulet' [test_browserElement_inproc_AppWindowNamespace.html] skip-if = toolkit == 'android' || buildapp == 'b2g' # android(TIMED_OUT, bug 783509) androidx86(TIMED_OUT, bug 783509) [test_browserElement_inproc_Auth.html] @@ -175,7 +175,7 @@ skip-if = buildapp == 'b2g' [test_browserElement_inproc_DOMRequestError.html] [test_browserElement_inproc_DataURI.html] [test_browserElement_inproc_DisallowEmbedAppsInOOP.html] -skip-if = os == "android" || toolkit == 'gonk' # embed-apps doesn't work in the mochitest app +skip-if = os == "android" || toolkit == 'gonk' || buildapp != 'mulet' # embed-apps doesn't work in the mochitest app [test_browserElement_inproc_DocumentFirstPaint.html] [test_browserElement_inproc_Download.html] disabled = bug 1022281 @@ -213,7 +213,7 @@ skip-if = (toolkit == 'gonk' && !debug) # Disabled on B2G Emulator because permission cannot be asserted in content process, # need to fix either bug 1094055 or bug 1020135. [test_browserElement_inproc_Proxy.html] -skip-if = (toolkit == 'gonk') +skip-if = toolkit == 'gonk' || buildapp == 'mulet' [test_browserElement_inproc_PurgeHistory.html] [test_browserElement_inproc_ReloadPostRequest.html] [test_browserElement_inproc_RemoveBrowserElement.html] diff --git a/dom/cache/test/mochitest/mochitest.ini b/dom/cache/test/mochitest/mochitest.ini index 63fcf08bb3..8395eb9c0f 100644 --- a/dom/cache/test/mochitest/mochitest.ini +++ b/dom/cache/test/mochitest/mochitest.ini @@ -42,7 +42,7 @@ support-files = [test_cache_restart.html] [test_cache_shrink.html] [test_cache_clear_on_app_uninstall.html] - skip-if = e10s || buildapp == 'b2g' # bug 1178685 + skip-if = buildapp != 'mulet' || e10s # bug 1178685 [test_cache_orphaned_cache.html] [test_cache_orphaned_body.html] [test_cache_untrusted.html] diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 979b202092..ddd0a0a712 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3488,13 +3488,9 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess virtual nscoord GetWidth() { - gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0, - mTextRun->GetLength(), - mDoMeasureBoundingBox ? - gfxFont::TIGHT_INK_EXTENTS : - gfxFont::LOOSE_INK_EXTENTS, - mDrawTarget, - nullptr); + gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText( + mDoMeasureBoundingBox ? gfxFont::TIGHT_INK_EXTENTS + : gfxFont::LOOSE_INK_EXTENTS, mDrawTarget); // this only measures the height; the total width is gotten from the // the return value of ProcessText. @@ -3524,13 +3520,10 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess // glyph string on OS X and DWrite where textrun widths may // involve fractional pixels. gfxTextRun::Metrics textRunMetrics = - mTextRun->MeasureText(0, - mTextRun->GetLength(), - mDoMeasureBoundingBox ? - gfxFont::TIGHT_INK_EXTENTS : - gfxFont::LOOSE_INK_EXTENTS, - mDrawTarget, - nullptr); + mTextRun->MeasureText(mDoMeasureBoundingBox ? + gfxFont::TIGHT_INK_EXTENTS : + gfxFont::LOOSE_INK_EXTENTS, + mDrawTarget); inlineCoord += textRunMetrics.mAdvanceWidth; // old code was: // point.x += width * mAppUnitsPerDevPixel; diff --git a/dom/datastore/tests/mochitest.ini b/dom/datastore/tests/mochitest.ini index 4cba8f7ff7..fda1c4c0c8 100644 --- a/dom/datastore/tests/mochitest.ini +++ b/dom/datastore/tests/mochitest.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = e10s +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') support-files = file_app_install.html file_readonly.html diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 586bced716..4ffc9aea73 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -658,10 +658,9 @@ ContentEventHandler::AppendFontRanges(FontRangeArray& aFontRanges, } } - uint32_t skipStart = iter.ConvertOriginalToSkipped(frameXPStart); - uint32_t skipEnd = iter.ConvertOriginalToSkipped(frameXPEnd); - gfxTextRun::GlyphRunIterator runIter( - textRun, skipStart, skipEnd - skipStart); + gfxTextRun::Range skipRange(iter.ConvertOriginalToSkipped(frameXPStart), + iter.ConvertOriginalToSkipped(frameXPEnd)); + gfxTextRun::GlyphRunIterator runIter(textRun, skipRange); int32_t lastXPEndOffset = frameXPStart; while (runIter.NextRun()) { gfxFont* font = runIter.GetGlyphRun()->mFont.get(); diff --git a/dom/events/test/test_all_synthetic_events.html b/dom/events/test/test_all_synthetic_events.html index 50d15c4311..c7ca5f9a82 100644 --- a/dom/events/test/test_all_synthetic_events.html +++ b/dom/events/test/test_all_synthetic_events.html @@ -489,7 +489,14 @@ const kEventConstructors = { return new SpeechRecognitionEvent(aName, aProps); }, }, + SpeechSynthesisErrorEvent: { create: function (aName, aProps) { + aProps.error = "synthesis-unavailable"; + aProps.utterance = new SpeechSynthesisUtterance("Hello World"); + return new SpeechSynthesisErrorEvent(aName, aProps); + }, + }, SpeechSynthesisEvent: { create: function (aName, aProps) { + aProps.utterance = new SpeechSynthesisUtterance("Hello World"); return new SpeechSynthesisEvent(aName, aProps); }, }, diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index 20a0ebbb05..1c3811e8f3 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -114,10 +114,10 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_app_isolation_inproc.html] # The app isolation tests are only supposed to run in the main process. -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s +skip-if = buildapp == 'b2g' || e10s [test_app_isolation_oop.html] # The app isolation tests are only supposed to run in the main process. -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s +skip-if = buildapp == 'b2g' || e10s [test_autoIncrement.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_autoIncrement_indexes.html] @@ -134,13 +134,13 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_crash.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_xhr_post.html] -skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116 +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_xhr_post_multifile.html] -skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116 +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_xhr_read.html] -skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116 +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blob_worker_xhr_read_slice.html] -skip-if = ((buildapp == 'b2g' && toolkit != 'gonk') || (e10s && toolkit == 'windows')) # Bug 931116 +skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_blocked_order.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_bug937006.html] @@ -361,14 +361,14 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116 [test_webapp_clearBrowserData_inproc_inproc.html] # The clearBrowserData tests are only supposed to run in the main process. # They currently time out on android. -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android' +skip-if = buildapp != 'mulet' [test_webapp_clearBrowserData_inproc_oop.html] # The clearBrowserData tests are only supposed to run in the main process. # They currently time out on android. -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android' +skip-if = buildapp != 'mulet' [test_webapp_clearBrowserData_oop_inproc.html] # The clearBrowserData tests are only supposed to run in the main process. # They currently time out on android. -skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s || toolkit == 'android' +skip-if = buildapp != 'mulet' [test_serviceworker.html] skip-if = buildapp == 'b2g' diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index df560ab2a0..0047226338 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -78,7 +78,7 @@ load 1080986.html load 1122218.html load 1127188.html load 1157994.html -load 1158427.html +skip-if(!B2G) load 1158427.html load 1185176.html load 1185192.html load analyser-channels-1.html diff --git a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp index b4886e918f..3cb9e1ba3a 100644 --- a/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp +++ b/dom/media/webspeech/synth/SpeechSynthesisUtterance.cpp @@ -162,6 +162,7 @@ SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventTy SpeechSynthesisEventInit init; init.mBubbles = false; init.mCancelable = false; + init.mUtterance = this; init.mCharIndex = aCharIndex; init.mElapsedTime = aElapsedTime; init.mName = aName; diff --git a/dom/media/webspeech/synth/test/file_setup.html b/dom/media/webspeech/synth/test/file_setup.html index a48754c2fa..d851349525 100644 --- a/dom/media/webspeech/synth/test/file_setup.html +++ b/dom/media/webspeech/synth/test/file_setup.html @@ -27,6 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444 ok(SpeechSynthesis, "SpeechSynthesis exists in global scope"); ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope"); +ok(SpeechSynthesisErrorEvent, "SpeechSynthesisErrorEvent exists in global scope"); ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope"); // SpeechSynthesisUtterance is the only type that has a constructor diff --git a/dom/messages/test/chrome.ini b/dom/messages/test/chrome.ini index cf8cbd4ad9..bdcc745bd5 100644 --- a/dom/messages/test/chrome.ini +++ b/dom/messages/test/chrome.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = (buildapp != "browser") || e10s +skip-if = e10s support-files = file_hasPendingMessage.html invalid_manifest.webapp @@ -8,4 +8,6 @@ support-files = manifest.webapp^headers^ [test_hasPendingMessage.html] +skip-if = buildapp != "browser" [test_sysmsg_registration.html] +skip-if = buildapp != 'mulet' diff --git a/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js b/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js index c1b26bded0..1bb31a6a48 100644 --- a/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js +++ b/dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js @@ -37,6 +37,9 @@ const TEST_DATA = [ }, { preferredNetworkType: "lte", expectedErrorMessage: "ModeNotSupported" + }, { + preferredNetworkType: "lte/wcdma", + expectedErrorMessage: "ModeNotSupported" }, // Test passing an invalid mode. We expect to get an exception here. { diff --git a/dom/network/NetworkStatsManager.js b/dom/network/NetworkStatsManager.js index 83644fc32d..1c3d5e3791 100644 --- a/dom/network/NetworkStatsManager.js +++ b/dom/network/NetworkStatsManager.js @@ -111,7 +111,6 @@ NetworkStatsAlarm.prototype = { const NETWORKSTATSMANAGER_CONTRACTID = "@mozilla.org/networkStatsManager;1"; const NETWORKSTATSMANAGER_CID = Components.ID("{ceb874cd-cc1a-4e65-b404-cc2d3e42425f}"); -const nsIDOMMozNetworkStatsManager = Ci.nsIDOMMozNetworkStatsManager; function NetworkStatsManager() { if (DEBUG) { @@ -122,40 +121,25 @@ function NetworkStatsManager() { NetworkStatsManager.prototype = { __proto__: DOMRequestIpcHelper.prototype, - checkPrivileges: function checkPrivileges() { - if (!this.hasPrivileges) { - throw Components.Exception("Permission denied", Cr.NS_ERROR_FAILURE); - } - }, - getSamples: function getSamples(aNetwork, aStart, aEnd, aOptions) { - this.checkPrivileges(); - - if (aStart.constructor.name !== "Date" || - aEnd.constructor.name !== "Date" || - !(aNetwork instanceof this.window.MozNetworkStatsInterface) || - aStart > aEnd) { + if (aStart > aEnd) { throw Components.results.NS_ERROR_INVALID_ARG; } - let appManifestURL = null; - let browsingTrafficOnly = false; - let serviceType = null; - if (aOptions) { - // appManifestURL is used to query network statistics by app; - // serviceType is used to query network statistics by system service. - // It is illegal to specify both of them at the same time. - if (aOptions.appManifestURL && aOptions.serviceType) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - } - // browsingTrafficOnly is meaningful only when querying by app. - if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - } - appManifestURL = aOptions.appManifestURL; - serviceType = aOptions.serviceType; - browsingTrafficOnly = aOptions.browsingTrafficOnly || false; + // appManifestURL is used to query network statistics by app; + // serviceType is used to query network statistics by system service. + // It is illegal to specify both of them at the same time. + if (aOptions.appManifestURL && aOptions.serviceType) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; } + // browsingTrafficOnly is meaningful only when querying by app. + if (!aOptions.appManifestURL && aOptions.browsingTrafficOnly) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + } + + let appManifestURL = aOptions.appManifestURL; + let serviceType = aOptions.serviceType; + let browsingTrafficOnly = aOptions.browsingTrafficOnly; // TODO Bug 929410 Date object cannot correctly pass through cpmm/ppmm IPC // This is just a work-around by passing timestamp numbers. @@ -175,12 +159,6 @@ NetworkStatsManager.prototype = { }, clearStats: function clearStats(aNetwork) { - this.checkPrivileges(); - - if (!aNetwork instanceof this.window.MozNetworkStatsInterface) { - throw Components.results.NS_ERROR_INVALID_ARG; - } - let request = this.createRequest(); cpmm.sendAsyncMessage("NetworkStats:Clear", { network: aNetwork.toJSON(), @@ -189,8 +167,6 @@ NetworkStatsManager.prototype = { }, clearAllStats: function clearAllStats() { - this.checkPrivileges(); - let request = this.createRequest(); cpmm.sendAsyncMessage("NetworkStats:ClearAll", {id: this.getRequestId(request)}); @@ -198,17 +174,6 @@ NetworkStatsManager.prototype = { }, addAlarm: function addAlarm(aNetwork, aThreshold, aOptions) { - this.checkPrivileges(); - - if (!aOptions) { - aOptions = Object.create(null); - } - - if (aOptions.startTime && aOptions.startTime.constructor.name !== "Date" || - !(aNetwork instanceof this.window.MozNetworkStatsInterface)) { - throw Components.results.NS_ERROR_INVALID_ARG; - } - let request = this.createRequest(); cpmm.sendAsyncMessage("NetworkStats:SetAlarm", {id: this.getRequestId(request), @@ -222,13 +187,8 @@ NetworkStatsManager.prototype = { }, getAllAlarms: function getAllAlarms(aNetwork) { - this.checkPrivileges(); - let network = null; if (aNetwork) { - if (!aNetwork instanceof this.window.MozNetworkStatsInterface) { - throw Components.results.NS_ERROR_INVALID_ARG; - } network = aNetwork.toJSON(); } @@ -241,8 +201,6 @@ NetworkStatsManager.prototype = { }, removeAlarms: function removeAlarms(aAlarmId) { - this.checkPrivileges(); - if (aAlarmId == 0) { aAlarmId = -1; } @@ -257,8 +215,6 @@ NetworkStatsManager.prototype = { }, getAvailableNetworks: function getAvailableNetworks() { - this.checkPrivileges(); - let request = this.createRequest(); cpmm.sendAsyncMessage("NetworkStats:GetAvailableNetworks", { id: this.getRequestId(request) }); @@ -266,8 +222,6 @@ NetworkStatsManager.prototype = { }, getAvailableServiceTypes: function getAvailableServiceTypes() { - this.checkPrivileges(); - let request = this.createRequest(); cpmm.sendAsyncMessage("NetworkStats:GetAvailableServiceTypes", { id: this.getRequestId(request) }); @@ -275,12 +229,10 @@ NetworkStatsManager.prototype = { }, get sampleRate() { - this.checkPrivileges(); return cpmm.sendSyncMessage("NetworkStats:SampleRate")[0]; }, get maxStorageAge() { - this.checkPrivileges(); return cpmm.sendSyncMessage("NetworkStats:MaxStorageAge")[0]; }, @@ -390,27 +342,7 @@ NetworkStatsManager.prototype = { }, init: function(aWindow) { - // Set navigator.mozNetworkStats to null. - if (!Services.prefs.getBoolPref("dom.mozNetworkStats.enabled")) { - return null; - } - let principal = aWindow.document.nodePrincipal; - let secMan = Services.scriptSecurityManager; - let perm = principal == secMan.getSystemPrincipal() ? - Ci.nsIPermissionManager.ALLOW_ACTION : - Services.perms.testExactPermissionFromPrincipal(principal, - "networkstats-manage"); - - // Only pages with perm set can use the netstats. - this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION; - if (DEBUG) { - debug("has privileges: " + this.hasPrivileges); - } - - if (!this.hasPrivileges) { - return null; - } this.initDOMRequestHelper(aWindow, ["NetworkStats:Get:Return", "NetworkStats:GetAvailableNetworks:Return", @@ -443,16 +375,10 @@ NetworkStatsManager.prototype = { }, classID : NETWORKSTATSMANAGER_CID, - QueryInterface : XPCOMUtils.generateQI([nsIDOMMozNetworkStatsManager, - Ci.nsIDOMGlobalPropertyInitializer, - Ci.nsISupportsWeakReference, - Ci.nsIObserver]), - - classInfo : XPCOMUtils.generateCI({classID: NETWORKSTATSMANAGER_CID, - contractID: NETWORKSTATSMANAGER_CONTRACTID, - classDescription: "NetworkStatsManager", - interfaces: [nsIDOMMozNetworkStatsManager], - flags: nsIClassInfo.DOM_OBJECT}) + contractID : NETWORKSTATSMANAGER_CONTRACTID, + QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer, + Ci.nsISupportsWeakReference, + Ci.nsIObserver]), } this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsAlarm, diff --git a/dom/network/NetworkStatsManager.manifest b/dom/network/NetworkStatsManager.manifest index 6231285731..8e8700910f 100644 --- a/dom/network/NetworkStatsManager.manifest +++ b/dom/network/NetworkStatsManager.manifest @@ -12,4 +12,3 @@ contract @mozilla.org/networkstatsalarm;1 {a93ea13e-409c-4189-9b1e-95fff220be55} component {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} NetworkStatsManager.js contract @mozilla.org/networkStatsManager;1 {ceb874cd-cc1a-4e65-b404-cc2d3e42425f} -category JavaScript-navigator-property mozNetworkStats @mozilla.org/networkStatsManager;1 diff --git a/dom/network/interfaces/moz.build b/dom/network/interfaces/moz.build index 4b23638405..e2aef2cb12 100644 --- a/dom/network/interfaces/moz.build +++ b/dom/network/interfaces/moz.build @@ -12,7 +12,6 @@ XPIDL_SOURCES += [ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': XPIDL_SOURCES += [ - 'nsIDOMNetworkStatsManager.idl', 'nsIEthernetManager.idl', 'nsINetworkStatsServiceProxy.idl', ] diff --git a/dom/network/tests/test_networkstats_alarms.html b/dom/network/tests/test_networkstats_alarms.html index 5fcaef568e..b02879738e 100644 --- a/dom/network/tests/test_networkstats_alarms.html +++ b/dom/network/tests/test_networkstats_alarms.html @@ -48,32 +48,30 @@ var steps = [ }; req.onerror = function () { - ok(req.error.name == "InvalidInterface", "Get InvalidInterface error"); + is(req.error.name, "InvalidInterface", "Get InvalidInterface error"); next(); } }, function () { ok(true, "Calling addAlarm() with invalid network or parameters."); + var msg = "TypeError: Not enough arguments to MozNetworkStatsManager.addAlarm."; try { navigator.mozNetworkStats.addAlarm(); } catch(ex) { - ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS, - "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no parameters"); + is(ex.toString(), msg, "addAlarm() throws \"" + msg + "\" when no parameters"); } try { navigator.mozNetworkStats.addAlarm(100000); } catch(ex) { - ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS, - "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no network"); + is(ex.toString(), msg, "addAlarm() throws " + msg + " when no network"); } try { navigator.mozNetworkStats.addAlarm(new window.MozNetworkStatsInterface(wifi)); } catch(ex) { - ok(ex.result == SpecialPowers.Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS, - "addAlarm() throws NS_ERROR_XPC_NOT_ENOUGH_ARGS exception when no threshold"); + is(ex.toString(), msg, "addAlarm() throws " + msg + " when no threshold"); } req = navigator.mozNetworkStats @@ -84,7 +82,7 @@ var steps = [ }; req.onerror = function () { - ok(req.error.name == "InvalidThresholdValue", "Get InvalidThresholdValue error"); + is(req.error.name, "InvalidThresholdValue", "Get InvalidThresholdValue error"); next(); } }, @@ -109,8 +107,8 @@ var steps = [ .getAllAlarms(new window.MozNetworkStatsInterface(wifi)); req.onsuccess = function () { - ok(req.result.length == 1, "Only one alarm"); - ok(req.result[0].alarmId == 1, "Get correct alarmId"); + is(req.result.length, 1, "Only one alarm"); + is(req.result[0].alarmId, 1, "Get correct alarmId"); next(); }; @@ -226,8 +224,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]}, ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist"); - ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager, - "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object"); + ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager, + "navigator.mozNetworkStats should be a MozNetworkStatsManager object"); test(); }); diff --git a/dom/network/tests/test_networkstats_basics.html b/dom/network/tests/test_networkstats_basics.html index 2f6df9bc97..df6f49c9c1 100644 --- a/dom/network/tests/test_networkstats_basics.html +++ b/dom/network/tests/test_networkstats_basics.html @@ -333,8 +333,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]}, ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist"); - ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager, - "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object"); + ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager, + "navigator.mozNetworkStats should be a MozNetworkStatsManager object"); test(); }); diff --git a/dom/network/tests/test_networkstats_disabled.html b/dom/network/tests/test_networkstats_disabled.html index f515d778c6..59fe68f3b5 100644 --- a/dom/network/tests/test_networkstats_disabled.html +++ b/dom/network/tests/test_networkstats_disabled.html @@ -22,10 +22,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", false]]}, ok(!SpecialPowers.getBoolPref("dom.mozNetworkStats.enabled"), "Preference 'dom.mozNetworkStats.enabled' is false."); - ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist"); - - is(navigator.mozNetworkStats, null, - "mozNetworkStats should be null when not enabled."); + ok(!('mozNetworkStats' in navigator), + "navigator.mozNetworkStats should not exist when pref not set"); SimpleTest.finish(); }); diff --git a/dom/network/tests/test_networkstats_enabled_no_perm.html b/dom/network/tests/test_networkstats_enabled_no_perm.html index 93c3e3e4c8..1ec321acc0 100644 --- a/dom/network/tests/test_networkstats_enabled_no_perm.html +++ b/dom/network/tests/test_networkstats_enabled_no_perm.html @@ -27,25 +27,11 @@ ok(!SpecialPowers.hasPermission("networkstats-manage", document), "Has no permission 'networkstats-manage'."); - ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist"); + ok(!('mozNetworkStats' in navigator), + "navigator.mozNetworkStats should not exist when permission not set"); - is(navigator.mozNetworkStats, null, - "mozNetworkStats should be null when no permission."); - - var error; - try { - navigator.mozNetworkStats.getAvailableNetworks; - - ok(false, - "Accessing navigator.mozNetworkStats.getAvailableNetworks should throw!"); - } catch (ex) { - error = ex; - } - - ok(error, - "Got an exception accessing navigator.mozNetworkStats.getAvailableNetworks"); - SimpleTest.finish(); -} + SimpleTest.finish(); + } diff --git a/dom/network/tests/test_networkstats_enabled_perm.html b/dom/network/tests/test_networkstats_enabled_perm.html index ceb32abe45..c22f8ecda6 100644 --- a/dom/network/tests/test_networkstats_enabled_perm.html +++ b/dom/network/tests/test_networkstats_enabled_perm.html @@ -30,8 +30,8 @@ SpecialPowers.pushPrefEnv({'set': [["dom.mozNetworkStats.enabled", true]]}, ok('mozNetworkStats' in navigator, "navigator.mozNetworkStats should exist"); - ok(navigator.mozNetworkStats instanceof SpecialPowers.Ci.nsIDOMMozNetworkStatsManager, - "navigator.mozNetworkStats should be a nsIDOMMozNetworkStatsManager object"); + ok(navigator.mozNetworkStats instanceof MozNetworkStatsManager, + "navigator.mozNetworkStats should be a MozNetworkStatsManager object"); SimpleTest.finish(); }); diff --git a/dom/network/tests/unit_stats/test_networkstats_db.js b/dom/network/tests/unit_stats/test_networkstats_db.js index 15e5b2c36e..9e7778d2ac 100644 --- a/dom/network/tests/unit_stats/test_networkstats_db.js +++ b/dom/network/tests/unit_stats/test_networkstats_db.js @@ -41,8 +41,8 @@ function filterTimestamp(date) { } function getNetworks() { - return [{ id: '0', type: Ci.nsIDOMMozNetworkStatsManager.WIFI }, - { id: '1234', type: Ci.nsIDOMMozNetworkStatsManager.MOBILE }]; + return [{ id: '0', type: Ci.nsINetworkInterface.NETWORK_TYPE_WIFI }, + { id: '1234', type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE }]; } function compareNetworks(networkA, networkB) { diff --git a/dom/network/tests/unit_stats/test_networkstats_service.js b/dom/network/tests/unit_stats/test_networkstats_service.js index 20bbcae61d..e0bf49ea1a 100644 --- a/dom/network/tests/unit_stats/test_networkstats_service.js +++ b/dom/network/tests/unit_stats/test_networkstats_service.js @@ -158,12 +158,12 @@ add_test(function test_queue() { }; // Fill networks with fake network interfaces to enable netd async requests. - var network = {id: "1234", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE}; + var network = {id: "1234", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE}; var netId1 = NetworkStatsService.getNetworkId(network.id, network.type); NetworkStatsService._networks[netId1] = { network: network, interfaceName: "net1" }; - network = {id: "5678", type: Ci.nsIDOMMozNetworkStatsManager.MOBILE}; + network = {id: "5678", type: Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE}; var netId2 = NetworkStatsService.getNetworkId(network.id, network.type); NetworkStatsService._networks[netId2] = { network: network, interfaceName: "net2" }; diff --git a/dom/permission/tests/mochitest.ini b/dom/permission/tests/mochitest.ini index 8a527ae287..ed586a0b02 100644 --- a/dom/permission/tests/mochitest.ini +++ b/dom/permission/tests/mochitest.ini @@ -18,6 +18,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(https not work [test_tcp-socket.html] [test_udp-socket.html] [test_webapps-manage.html] +skip-if = buildapp != 'b2g' && buildapp != 'mulet' [test_camera.html] disabled = disabled until bug 859593 is fixed [test_keyboard.html] diff --git a/dom/permission/tests/test_networkstats-manage.html b/dom/permission/tests/test_networkstats-manage.html index 9eefe6a8a3..4fdc847717 100644 --- a/dom/permission/tests/test_networkstats-manage.html +++ b/dom/permission/tests/test_networkstats-manage.html @@ -20,7 +20,7 @@ var gData = [ { perm: ["networkstats-manage"], obj: "mozNetworkStats", - idl: "nsIDOMMozNetworkStatsManager", + webidl: "MozNetworkStatsManager", settings: [["dom.mozNetworkStats.enabled", true]], }, ] diff --git a/dom/requestsync/tests/mochitest.ini b/dom/requestsync/tests/mochitest.ini index 96f937990e..1a3018f365 100644 --- a/dom/requestsync/tests/mochitest.ini +++ b/dom/requestsync/tests/mochitest.ini @@ -14,7 +14,7 @@ skip-if = os == "android" || toolkit == "gonk" [test_basic.html] skip-if = os == "android" || toolkit == "gonk" [test_basic_app.html] -skip-if = os == "android" || buildapp == 'b2g' || e10s # mozapps +skip-if = buildapp != 'mulet' || e10s # mozapps [test_wakeUp.html] run-if = buildapp == 'b2g' && toolkit == 'gonk' [test_runNow.html] diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini index fae1bb1c7c..92e061f700 100644 --- a/dom/security/test/csp/mochitest.ini +++ b/dom/security/test/csp/mochitest.ini @@ -176,6 +176,7 @@ skip-if = buildapp == 'b2g' #no ssl support [test_ignore_unsafe_inline.html] [test_self_none_as_hostname_confusion.html] [test_bug949549.html] +skip-if = buildapp != 'b2g' && buildapp != 'mulet' [test_path_matching.html] [test_path_matching_redirect.html] [test_report_uri_missing_in_report_only_header.html] diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index e3d46b6f65..af5b9d8e10 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -390,6 +390,7 @@ this.GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY = "evdo"; this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO = "wcdma/gsm/cdma/evdo"; this.GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = "lte/cdma/evdo"; this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM = "lte/wcdma/gsm"; +this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA = "lte/wcdma"; this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO = "lte/wcdma/gsm/cdma/evdo"; this.GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY = "lte"; this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [ @@ -404,7 +405,8 @@ this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [ GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO, GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM, GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY + GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY, + GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA ]; this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma"; diff --git a/dom/tests/mochitest/fetch/mochitest.ini b/dom/tests/mochitest/fetch/mochitest.ini index 1282d7ff83..0952705946 100644 --- a/dom/tests/mochitest/fetch/mochitest.ini +++ b/dom/tests/mochitest/fetch/mochitest.ini @@ -21,25 +21,34 @@ support-files = [test_headers_sw_reroute.html] skip-if = buildapp == 'b2g' # Bug 1137683 [test_headers_mainthread.html] +skip-if = (e10s && debug && os == 'win') [test_fetch_app_protocol.html] +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') [test_fetch_basic.html] +skip-if = (e10s && debug && os == 'win') [test_fetch_basic_sw_reroute.html] -skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683 [test_fetch_basic_http.html] +skip-if = (e10s && debug && os == 'win') [test_fetch_basic_http_sw_reroute.html] -skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g +skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683 [test_fetch_cors.html] -skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210552 && 1210282 +skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) || (e10s && debug && os == 'win') # Bug 1210552 && 1210282 [test_fetch_cors_sw_reroute.html] -skip-if = e10s || buildapp == 'b2g' # Bug 1173163 for e10s, bug 1137683 for b2g +skip-if = buildapp == 'b2g' || (toolkit == 'android' && debug) # Bug 1210282 [test_formdataparsing.html] +skip-if = (e10s && debug && os == 'win') [test_formdataparsing_sw_reroute.html] -skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683 [test_request.html] +skip-if = (e10s && debug && os == 'win') [test_request_cache.html] +skip-if = (e10s && debug && os == 'win') [test_request_context.html] +skip-if = (e10s && debug && os == 'win') [test_request_sw_reroute.html] -skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683 [test_response.html] +skip-if = (e10s && debug && os == 'win') [test_response_sw_reroute.html] -skip-if = buildapp == 'b2g' # Bug 1137683 +skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1137683 diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 8911c86b27..0ef287f403 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -1034,17 +1034,19 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! {name: "SimpleTest", xbl: false}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SourceBuffer", desktop: true, linux: false, release: false}, + "SourceBuffer", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SourceBufferList", desktop: true, linux: false, release: false}, + "SourceBufferList", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisEvent", b2g: true}, + {name: "SpeechSynthesisErrorEvent", android: false, nightly: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesis", b2g: true}, + {name: "SpeechSynthesisEvent", android: false, nightly: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisUtterance", b2g: true}, + {name: "SpeechSynthesis", android: false, nightly: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisVoice", b2g: true}, + {name: "SpeechSynthesisUtterance", android: false, nightly: true}, +// IMPORTANT: Do not change this list without review from a DOM peer! + {name: "SpeechSynthesisVoice", android: false, nightly: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "SpecialPowers", xbl: false}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/tests/mochitest/localstorage/chrome.ini b/dom/tests/mochitest/localstorage/chrome.ini index 3c4a3362dc..a96487025c 100644 --- a/dom/tests/mochitest/localstorage/chrome.ini +++ b/dom/tests/mochitest/localstorage/chrome.ini @@ -5,7 +5,9 @@ support-files = page_blank.html [test_app_uninstall.html] +skip-if = buildapp != 'mulet' [test_clear_browser_data.html] +skip-if = buildapp != 'mulet' [test_localStorageBasePrivateBrowsing_perwindowpb.html] [test_localStorageFromChrome.xhtml] [test_localStorageQuotaPrivateBrowsing_perwindowpb.html] diff --git a/dom/tests/mochitest/localstorage/test_app_uninstall.html b/dom/tests/mochitest/localstorage/test_app_uninstall.html index 744d3dc8aa..1960326237 100644 --- a/dom/tests/mochitest/localstorage/test_app_uninstall.html +++ b/dom/tests/mochitest/localstorage/test_app_uninstall.html @@ -152,7 +152,7 @@ function browserLoadEvent() { setupStorage(gBrowserStorage.localStorage); setupStorage(gBrowserStorage.sessionStorage); - navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() { + navigator.mozApps.mgmt.getAll().onsuccess = function() { for (i in this.result) { var app = this.result[i]; if (app.manifestURL == gManifestURL) { diff --git a/dom/tests/mochitest/notification/mochitest.ini b/dom/tests/mochitest/notification/mochitest.ini index 6b9829779c..539ea03a5e 100644 --- a/dom/tests/mochitest/notification/mochitest.ini +++ b/dom/tests/mochitest/notification/mochitest.ini @@ -8,6 +8,6 @@ support-files = [test_notification_storage.html] [test_bug931307.html] [test_notification_resend.html] -skip-if = e10s # On e10s, faking the app seems to be failing +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || e10s # On e10s, faking the app seems to be failing [test_notification_noresend.html] skip-if = (toolkit == 'gonk') # Mochitest on Gonk registers an app manifest that messes with the logic diff --git a/dom/webidl/InterAppMessagePort.webidl b/dom/webidl/InterAppMessagePort.webidl index 9f23f9b89e..3bcf433fb1 100644 --- a/dom/webidl/InterAppMessagePort.webidl +++ b/dom/webidl/InterAppMessagePort.webidl @@ -21,4 +21,5 @@ interface MozInterAppMessagePort : EventTarget { void close(); attribute EventHandler onmessage; + attribute EventHandler onclose; }; diff --git a/dom/webidl/Location.webidl b/dom/webidl/Location.webidl index 6f59cb802b..3d6b39ff9f 100644 --- a/dom/webidl/Location.webidl +++ b/dom/webidl/Location.webidl @@ -40,10 +40,10 @@ interface Location { attribute USVString hash; [Throws, UnsafeInPrerendering] - void assign(DOMString url); + void assign(USVString url); [Throws, CrossOriginCallable, UnsafeInPrerendering] - void replace(DOMString url); + void replace(USVString url); // XXXbz there is no forceget argument in the spec! See bug 1037721. [Throws, UnsafeInPrerendering] diff --git a/dom/webidl/MediaStreamTrack.webidl b/dom/webidl/MediaStreamTrack.webidl index fea064e5db..bea5228870 100644 --- a/dom/webidl/MediaStreamTrack.webidl +++ b/dom/webidl/MediaStreamTrack.webidl @@ -63,24 +63,26 @@ dictionary MediaTrackConstraints : MediaTrackConstraintSet { sequence advanced; }; -interface MediaStreamTrack { +[Exposed=Window] +interface MediaStreamTrack : EventTarget { readonly attribute DOMString kind; readonly attribute DOMString id; readonly attribute DOMString label; attribute boolean enabled; -// readonly attribute MediaStreamTrackState readyState; -// readonly attribute SourceTypeEnum sourceType; -// readonly attribute DOMString sourceId; -// attribute EventHandler onstarted; -// attribute EventHandler onmute; -// attribute EventHandler onunmute; +// readonly attribute boolean muted; +// attribute EventHandler onmute; +// attribute EventHandler onunmute; +// readonly attribute boolean _readonly; +// readonly attribute boolean remote; +// readonly attribute MediaStreamTrackState readyState; // attribute EventHandler onended; -// any getConstraint (DOMString constraintName, optional boolean mandatory = false); -// void setConstraint (DOMString constraintName, any constraintValue, optional boolean mandatory = false); -// MediaTrackConstraints? constraints (); -// void applyConstraints (MediaTrackConstraints constraints); -// void prependConstraint (DOMString constraintName, any constraintValue); -// void appendConstraint (DOMString constraintName, any constraintValue); -// attribute EventHandler onoverconstrained; +// MediaStreamTrack clone (); void stop (); +// MediaTrackCapabilities getCapabilities (); +// MediaTrackConstraints getConstraints (); +// MediaTrackSettings getSettings (); + + [Throws] + Promise applyConstraints (optional MediaTrackConstraints constraints); +// attribute EventHandler onoverconstrained; }; diff --git a/dom/webidl/MozMobileConnection.webidl b/dom/webidl/MozMobileConnection.webidl index 1d9c9d4047..13ade08dcc 100644 --- a/dom/webidl/MozMobileConnection.webidl +++ b/dom/webidl/MozMobileConnection.webidl @@ -9,7 +9,7 @@ enum MobilePreferredNetworkType {"wcdma/gsm", "gsm", "wcdma", "wcdma/gsm-auto", "cdma/evdo", "cdma", "evdo", "wcdma/gsm/cdma/evdo", "lte/cdma/evdo", "lte/wcdma/gsm", "lte/wcdma/gsm/cdma/evdo", - "lte"}; + "lte", "lte/wcdma"}; enum MobileRoamingMode {"home", "affiliated", "any"}; [Pref="dom.mobileconnection.enabled"] @@ -190,7 +190,7 @@ interface MozMobileConnection : EventTarget * result will be a string indicating the current preferred network type. * The value will be either 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', * 'cdma/evdo', 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', 'lte/cdma/evdo', - * 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo' or 'lte'. + * 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo', 'lte' or 'lte/wcdma'. * * Otherwise, the request's onerror will be called, and the request's error * will be either 'RadioNotAvailable', 'RequestNotSupported', diff --git a/dom/webidl/MozNetworkStats.webidl b/dom/webidl/MozNetworkStats.webidl index eb9713b617..27243f3ba2 100644 --- a/dom/webidl/MozNetworkStats.webidl +++ b/dom/webidl/MozNetworkStats.webidl @@ -14,15 +14,15 @@ dictionary NetworkStatsGetOptions * Note that, these two options cannot be specified at the same time for now; * others, an NS_ERROR_NOT_IMPLMENTED exception will be thrown. */ - DOMString appManifestURL; - DOMString serviceType; + DOMString? appManifestURL = null; + DOMString serviceType = ""; /** * If it is set as true, only the browsing traffic, which is generated from * the mozbrowser iframe element within an app, is returned in result. * If it is set as false or not set, the total traffic, which is generated * from both the mozapp and mozbrowser iframe elements, is returned. */ - boolean browsingTrafficOnly; + boolean browsingTrafficOnly = false; }; dictionary NetworkStatsAlarmOptions diff --git a/dom/network/interfaces/nsIDOMNetworkStatsManager.idl b/dom/webidl/MozNetworkStatsManager.webidl similarity index 65% rename from dom/network/interfaces/nsIDOMNetworkStatsManager.idl rename to dom/webidl/MozNetworkStatsManager.webidl index 9db848af10..0295e40787 100644 --- a/dom/network/interfaces/nsIDOMNetworkStatsManager.idl +++ b/dom/webidl/MozNetworkStatsManager.webidl @@ -1,14 +1,14 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ -#include "nsISupports.idl" - -interface nsIDOMDOMRequest; - -[scriptable, uuid(72c4e583-389d-4d1b-9424-702feabb6055)] -interface nsIDOMMozNetworkStatsManager : nsISupports -{ +[NavigatorProperty="mozNetworkStats", + JSImplementation="@mozilla.org/networkStatsManager;1", + CheckAnyPermissions="networkstats-manage", + Pref="dom.mozNetworkStats.enabled"] +interface MozNetworkStatsManager { /** * Constants for known interface types. */ @@ -21,12 +21,12 @@ interface nsIDOMMozNetworkStatsManager : nsISupports * If options is provided, per-app or per-system service usage will be * retrieved; otherwise the target will be overall system usage. * - * If success, the request result will be an nsIDOMMozNetworkStats object. + * If success, the request result will be an MozNetworkStats object. */ - nsIDOMDOMRequest getSamples(in nsISupports network, - in jsval start, - in jsval end, - [optional] in jsval options /* NetworkStatsGetOptions */); + DOMRequest getSamples(MozNetworkStatsInterface network, + Date start, + Date end, + optional NetworkStatsGetOptions options); /** * Install an alarm on a network. The network must be in the return of @@ -39,9 +39,9 @@ interface nsIDOMMozNetworkStatsManager : nsISupports * * If success, the |result| field of the DOMRequest keeps the alarm Id. */ - nsIDOMDOMRequest addAlarm(in nsISupports network, - in long long threshold, - [optional] in jsval options /* NetworkStatsAlarmOptions */); + DOMRequest addAlarm(MozNetworkStatsInterface network, + long long threshold, + optional NetworkStatsAlarmOptions options); /** * Obtain all alarms for those networks returned by getAvailableNetworks(). @@ -55,33 +55,33 @@ interface nsIDOMMozNetworkStatsManager : nsISupports * - threshold * - data */ - nsIDOMDOMRequest getAllAlarms([optional] in nsISupports network); + DOMRequest getAllAlarms(optional MozNetworkStatsInterface network); /** * Remove all network alarms. If an |alarmId| is provided, then only that * alarm is removed. */ - nsIDOMDOMRequest removeAlarms([optional] in long alarmId); + DOMRequest removeAlarms(optional unsigned long alarmId = 0); /** * Remove all stats related with the provided network from DB. */ - nsIDOMDOMRequest clearStats(in nsISupports network); + DOMRequest clearStats(MozNetworkStatsInterface network); /** * Remove all stats in the database. */ - nsIDOMDOMRequest clearAllStats(); + DOMRequest clearAllStats(); /** * Return available networks that used to be saved in the database. */ - nsIDOMDOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface. + DOMRequest getAvailableNetworks(); // array of MozNetworkStatsInterface. /** * Return available service types that used to be saved in the database. */ - nsIDOMDOMRequest getAvailableServiceTypes(); // array of string. + DOMRequest getAvailableServiceTypes(); // array of string. /** * Minimum time in milliseconds between samples stored in the database. diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index b70832d9af..6c30c12cf2 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -54,8 +54,10 @@ interface NavigatorID { [NoInterfaceObject, Exposed=(Window,Worker)] interface NavigatorLanguage { - // These 2 values are cached. They are updated when pref - // intl.accept_languages is changed. + // These two attributes are cached because this interface is also implemented + // by Workernavigator and this way we don't have to go back to the + // main-thread from the worker thread anytime we need to retrieve them. They + // are updated when pref intl.accept_languages is changed. [Pure, Cached] readonly attribute DOMString? language; @@ -98,7 +100,7 @@ interface NavigatorFeatures { }; partial interface Navigator { - [Throws, Pref="dom.permissions.enabled"] + [Throws] readonly attribute Permissions permissions; }; @@ -188,7 +190,7 @@ Navigator implements NavigatorMobileId; // nsIDOMNavigator partial interface Navigator { - [Throws] + [Throws, Constant, Cached] readonly attribute DOMString oscpu; // WebKit/Blink support this; Trident/Presto do not. readonly attribute DOMString vendor; @@ -198,7 +200,7 @@ partial interface Navigator { readonly attribute DOMString productSub; // WebKit/Blink/Trident/Presto support this. readonly attribute boolean cookieEnabled; - [Throws] + [Throws, Constant, Cached] readonly attribute DOMString buildID; [Throws, CheckAnyPermissions="power", UnsafeInPrerendering] readonly attribute MozPowerManager mozPower; @@ -418,7 +420,7 @@ partial interface Navigator { // Service Workers/Navigation Controllers partial interface Navigator { - [Func="ServiceWorkerContainer::IsEnabled"] + [Func="ServiceWorkerContainer::IsEnabled", SameObject] readonly attribute ServiceWorkerContainer serviceWorker; }; diff --git a/dom/webidl/NotificationEvent.webidl b/dom/webidl/NotificationEvent.webidl index e92e33a191..b5099e6a21 100644 --- a/dom/webidl/NotificationEvent.webidl +++ b/dom/webidl/NotificationEvent.webidl @@ -11,7 +11,7 @@ * related or neighboring rights to this work. */ -[Constructor(DOMString type, optional NotificationEventInit eventInitDict), +[Constructor(DOMString type, NotificationEventInit eventInitDict), Exposed=ServiceWorker,Func="mozilla::dom::Notification::PrefEnabled"] interface NotificationEvent : ExtendableEvent { readonly attribute Notification notification; diff --git a/dom/webidl/PermissionStatus.webidl b/dom/webidl/PermissionStatus.webidl index 27ae490c39..3abfd66f40 100644 --- a/dom/webidl/PermissionStatus.webidl +++ b/dom/webidl/PermissionStatus.webidl @@ -13,8 +13,7 @@ enum PermissionState { "prompt" }; -[Exposed=(Window), - Pref="dom.permissions.enabled"] +[Exposed=(Window)] interface PermissionStatus : EventTarget { readonly attribute PermissionState state; attribute EventHandler onchange; diff --git a/dom/webidl/Permissions.webidl b/dom/webidl/Permissions.webidl index fa1f6d874a..0c7f8f30d0 100644 --- a/dom/webidl/Permissions.webidl +++ b/dom/webidl/Permissions.webidl @@ -22,8 +22,7 @@ dictionary PushPermissionDescriptor : PermissionDescriptor { boolean userVisible = false; }; -[Exposed=(Window), - Pref="dom.permissions.enabled"] +[Exposed=(Window)] interface Permissions { [Throws] Promise query(object permission); diff --git a/dom/webidl/SpeechSynthesisErrorEvent.webidl b/dom/webidl/SpeechSynthesisErrorEvent.webidl new file mode 100644 index 0000000000..1388755d31 --- /dev/null +++ b/dom/webidl/SpeechSynthesisErrorEvent.webidl @@ -0,0 +1,36 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * The origin of this IDL file is + * http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html + * + * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +enum SpeechSynthesisErrorCode { + "canceled", + "interrupted", + "audio-busy", + "audio-hardware", + "network", + "synthesis-unavailable", + "synthesis-failed", + "language-unavailable", + "voice-unavailable", + "text-too-long", + "invalid-argument", +}; + +[Constructor(DOMString type, SpeechSynthesisErrorEventInit eventInitDict), + Pref="media.webspeech.synth.enabled"] +interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent { + readonly attribute SpeechSynthesisErrorCode error; +}; + +dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit +{ + required SpeechSynthesisErrorCode error; +}; diff --git a/dom/webidl/SpeechSynthesisEvent.webidl b/dom/webidl/SpeechSynthesisEvent.webidl index 029eeb2476..a5f8b3c2b3 100644 --- a/dom/webidl/SpeechSynthesisEvent.webidl +++ b/dom/webidl/SpeechSynthesisEvent.webidl @@ -10,10 +10,11 @@ * liability, trademark and document use rules apply. */ -[Constructor(DOMString type, optional SpeechSynthesisEventInit eventInitDict), +[Constructor(DOMString type, SpeechSynthesisEventInit eventInitDict), Pref="media.webspeech.synth.enabled"] interface SpeechSynthesisEvent : Event { + readonly attribute SpeechSynthesisUtterance utterance; readonly attribute unsigned long charIndex; readonly attribute float elapsedTime; readonly attribute DOMString? name; @@ -21,6 +22,7 @@ interface SpeechSynthesisEvent : Event dictionary SpeechSynthesisEventInit : EventInit { + required SpeechSynthesisUtterance utterance; unsigned long charIndex = 0; float elapsedTime = 0; DOMString name = ""; diff --git a/dom/webidl/TreeColumn.webidl b/dom/webidl/TreeColumn.webidl index a4e02f5791..6d843a078a 100644 --- a/dom/webidl/TreeColumn.webidl +++ b/dom/webidl/TreeColumn.webidl @@ -25,6 +25,7 @@ interface TreeColumn { const short TYPE_TEXT = 1; const short TYPE_CHECKBOX = 2; const short TYPE_PROGRESSMETER = 3; + const short TYPE_PASSWORD = 4; readonly attribute short type; TreeColumn? getNext(); diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl index 4f7cbb20f4..3cfd1400c7 100644 --- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -236,7 +236,6 @@ interface WebGL2RenderingContext : WebGLRenderingContext const GLenum RGB8_SNORM = 0x8F96; const GLenum RGBA8_SNORM = 0x8F97; const GLenum SIGNED_NORMALIZED = 0x8F9C; - const GLenum PRIMITIVE_RESTART_FIXED_INDEX = 0x8D69; const GLenum COPY_READ_BUFFER = 0x8F36; const GLenum COPY_WRITE_BUFFER = 0x8F37; const GLenum COPY_READ_BUFFER_BINDING = 0x8F36; /* Same as COPY_READ_BUFFER */ @@ -289,10 +288,6 @@ interface WebGL2RenderingContext : WebGLRenderingContext const GLenum ANY_SAMPLES_PASSED_CONSERVATIVE = 0x8D6A; const GLenum SAMPLER_BINDING = 0x8919; const GLenum RGB10_A2UI = 0x906F; - const GLenum TEXTURE_SWIZZLE_R = 0x8E42; - const GLenum TEXTURE_SWIZZLE_G = 0x8E43; - const GLenum TEXTURE_SWIZZLE_B = 0x8E44; - const GLenum TEXTURE_SWIZZLE_A = 0x8E45; const GLenum GREEN = 0x1904; const GLenum BLUE = 0x1905; const GLenum INT_2_10_10_10_REV = 0x8D9F; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 2c4d2bee0b..922e688447 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -69,7 +69,7 @@ typedef any Transferable; #ifdef HAVE_SIDEBAR [Replaceable, Throws] readonly attribute External external; #endif - [Throws] readonly attribute ApplicationCache applicationCache; + [Throws, Pref="browser.cache.offline.enable"] readonly attribute ApplicationCache applicationCache; // user prompts [Throws, UnsafeInPrerendering] void alert(); @@ -269,7 +269,7 @@ Window implements WindowModal; // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches partial interface Window { -[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled"] +[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject] readonly attribute CacheStorage caches; }; diff --git a/dom/webidl/Worker.webidl b/dom/webidl/Worker.webidl index 6376fedfa6..158a502d60 100644 --- a/dom/webidl/Worker.webidl +++ b/dom/webidl/Worker.webidl @@ -14,7 +14,7 @@ [Constructor(DOMString scriptURL), Func="mozilla::dom::workers::WorkerPrivate::WorkerAvailable", - Exposed=(Window,Worker,System)] + Exposed=(Window,DedicatedWorker,SharedWorker,System)] interface Worker : EventTarget { void terminate(); @@ -28,6 +28,6 @@ Worker implements AbstractWorker; [Constructor(DOMString scriptURL), Func="mozilla::dom::workers::ChromeWorkerPrivate::WorkerAvailable", - Exposed=(Window,Worker,System)] + Exposed=(Window,DedicatedWorker,SharedWorker,System)] interface ChromeWorker : Worker { }; diff --git a/dom/webidl/WorkerGlobalScope.webidl b/dom/webidl/WorkerGlobalScope.webidl index f56eb40802..3ea893d73a 100644 --- a/dom/webidl/WorkerGlobalScope.webidl +++ b/dom/webidl/WorkerGlobalScope.webidl @@ -40,7 +40,7 @@ partial interface WorkerGlobalScope { // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#self-caches partial interface WorkerGlobalScope { -[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled"] +[Throws, Func="mozilla::dom::cache::CacheStorage::PrefEnabled", SameObject] readonly attribute CacheStorage caches; }; diff --git a/dom/webidl/XMLHttpRequest.webidl b/dom/webidl/XMLHttpRequest.webidl index d5cf4962cb..9af72f9c6d 100644 --- a/dom/webidl/XMLHttpRequest.webidl +++ b/dom/webidl/XMLHttpRequest.webidl @@ -54,7 +54,7 @@ dictionary MozXMLHttpRequestParameters // c = new(window.ActiveXObject || XMLHttpRequest)("Microsoft.XMLHTTP") // To handle that, we need a constructor that takes a string. Constructor(DOMString ignored), - Exposed=(Window,Worker)] + Exposed=(Window,DedicatedWorker,SharedWorker)] interface XMLHttpRequest : XMLHttpRequestEventTarget { // event handler attribute EventHandler onreadystatechange; diff --git a/dom/webidl/XMLHttpRequestEventTarget.webidl b/dom/webidl/XMLHttpRequestEventTarget.webidl index 39c2c53f59..f16634355b 100644 --- a/dom/webidl/XMLHttpRequestEventTarget.webidl +++ b/dom/webidl/XMLHttpRequestEventTarget.webidl @@ -10,7 +10,7 @@ * liability, trademark and document use rules apply. */ -[Exposed=(Window,Worker)] +[Exposed=(Window,DedicatedWorker,SharedWorker)] interface XMLHttpRequestEventTarget : EventTarget { // event handlers [SetterThrows=Workers, GetterThrows=Workers] diff --git a/dom/webidl/XMLHttpRequestUpload.webidl b/dom/webidl/XMLHttpRequestUpload.webidl index 002b892c26..cbb8728b7a 100644 --- a/dom/webidl/XMLHttpRequestUpload.webidl +++ b/dom/webidl/XMLHttpRequestUpload.webidl @@ -10,7 +10,7 @@ * liability, trademark and document use rules apply. */ -[Exposed=(Window,Worker)] +[Exposed=(Window,DedicatedWorker,SharedWorker)] interface XMLHttpRequestUpload : XMLHttpRequestEventTarget { }; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 3c947501c3..92232b5935 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -32,7 +32,6 @@ WEBIDL_FILES = [ 'AnonymousContent.webidl', 'AppInfo.webidl', 'AppNotificationServiceOptions.webidl', - 'Apps.webidl', 'APZTestData.webidl', 'ArchiveReader.webidl', 'ArchiveRequest.webidl', @@ -631,7 +630,7 @@ if CONFIG['MOZ_WEBRTC']: 'PeerConnectionImplEnums.webidl', 'PeerConnectionObserver.webidl', 'PeerConnectionObserverEnums.webidl', - 'RTCCertificate.webidl', + 'RTCCertificate.webidl', 'RTCConfiguration.webidl', 'RTCIceCandidate.webidl', 'RTCIdentityAssertion.webidl', @@ -656,6 +655,7 @@ if CONFIG['MOZ_WEBSPEECH']: 'SpeechRecognitionResult.webidl', 'SpeechRecognitionResultList.webidl', 'SpeechSynthesis.webidl', + 'SpeechSynthesisErrorEvent.webidl', 'SpeechSynthesisEvent.webidl', 'SpeechSynthesisUtterance.webidl', 'SpeechSynthesisVoice.webidl', @@ -673,7 +673,6 @@ WEBIDL_FILES += [ 'DeviceStorageChangeEvent.webidl', 'DOMTransactionEvent.webidl', 'HashChangeEvent.webidl', - 'MozApplicationEvent.webidl', 'MozSettingsEvent.webidl', 'PageTransitionEvent.webidl', 'PopStateEvent.webidl', @@ -751,6 +750,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': 'MozNetworkStatsAlarm.webidl', 'MozNetworkStatsData.webidl', 'MozNetworkStatsInterface.webidl', + 'MozNetworkStatsManager.webidl', 'MozSpeakerManager.webidl', 'MozWifiCapabilities.webidl', 'MozWifiManager.webidl', @@ -795,7 +795,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'IccChangeEvent.webidl', 'ImageCaptureErrorEvent.webidl', 'MediaStreamEvent.webidl', - 'MozApplicationEvent.webidl', 'MozCellBroadcastEvent.webidl', 'MozClirModeEvent.webidl', 'MozContactChangeEvent.webidl', @@ -845,6 +844,7 @@ if CONFIG['MOZ_WEBRTC']: if CONFIG['MOZ_WEBSPEECH']: GENERATED_EVENTS_WEBIDL_FILES += [ 'SpeechRecognitionEvent.webidl', + 'SpeechSynthesisErrorEvent.webidl', 'SpeechSynthesisEvent.webidl', ] @@ -906,5 +906,10 @@ if CONFIG['MOZ_PAY']: if CONFIG['MOZ_B2G']: WEBIDL_FILES += [ - 'Identity.webidl' + 'Apps.webidl', + 'Identity.webidl', + 'MozApplicationEvent.webidl' + ] + GENERATED_EVENTS_WEBIDL_FILES += [ + 'MozApplicationEvent.webidl' ] diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 4ab9880413..ec71a93baf 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -190,12 +190,6 @@ var interfaceNamesInGlobalScope = "TextDecoder", // IMPORTANT: Do not change this list without review from a DOM peer! "TextEncoder", -// IMPORTANT: Do not change this list without review from a DOM peer! - "XMLHttpRequest", -// IMPORTANT: Do not change this list without review from a DOM peer! - "XMLHttpRequestEventTarget", -// IMPORTANT: Do not change this list without review from a DOM peer! - "XMLHttpRequestUpload", // IMPORTANT: Do not change this list without review from a DOM peer! "URL", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/extensions/cookie/test/chrome.ini b/extensions/cookie/test/chrome.ini index 76bb729f77..99dce343dd 100644 --- a/extensions/cookie/test/chrome.ini +++ b/extensions/cookie/test/chrome.ini @@ -3,5 +3,8 @@ skip-if = buildapp == 'b2g' support-files = channel_utils.js [test_app_uninstall_cookies.html] +skip-if = buildapp != 'mulet' [test_app_uninstall_permissions.html] +skip-if = buildapp != 'mulet' + [test_permissionmanager_app_isolation.html] diff --git a/extensions/cookie/test/test_app_uninstall_cookies.html b/extensions/cookie/test/test_app_uninstall_cookies.html index 165bd27942..14a2499e63 100644 --- a/extensions/cookie/test/test_app_uninstall_cookies.html +++ b/extensions/cookie/test/test_app_uninstall_cookies.html @@ -158,8 +158,7 @@ function checkCookie() { gCurrentCookiesCount = getCookiesCount() - appCookiesCount; - // Not installed means not installed as native app. - navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() { + navigator.mozApps.mgmt.getAll().onsuccess = function() { for (i in this.result) { var app = this.result[i]; if (app.manifestURL == gManifestURL) { diff --git a/extensions/cookie/test/test_app_uninstall_permissions.html b/extensions/cookie/test/test_app_uninstall_permissions.html index 63455db011..6b69df6776 100644 --- a/extensions/cookie/test/test_app_uninstall_permissions.html +++ b/extensions/cookie/test/test_app_uninstall_permissions.html @@ -60,12 +60,17 @@ SimpleTest.registerCleanupFunction(() => var gManifestURL = "http://www.example.com/chrome/dom/tests/mochitest/webapps/apps/basic.webapp"; +// Get the permission count before installing the app so we can compare it to +// the permission count after uninstalling the app. +var currentPermissionCount = getPermissionCountForApp(-1); + function onInstall() { var testAppId = appsService.getAppLocalIdByManifestURL(gManifestURL); - is(getPermissionCountForApp(testAppId), 0, "App should have no permission"); - - var currentPermissionCount = getPermissionCountForApp(-1); + // PermissionsManager.installPermissions gets run during the install process, + // and it adds the "indexedDB" permission by default, so the app should have + // that permission. + is(getPermissionCountForApp(testAppId), 1, "App should have 1 permission"); var attrs = {appId: testAppId}; var principal = secMan.createCodebasePrincipal(ioService.newURI("http://www.example.com", null, null), @@ -85,10 +90,9 @@ function onInstall() { attrs); permManager.addFromPrincipal(principal, "foobar", Ci.nsIPermissionManager.ALLOW_ACTION); - is(getPermissionCountForApp(testAppId), 5, "App should have 5 permissions"); + is(getPermissionCountForApp(testAppId), 6, "App should have 6 permissions"); - // Not installed means not installed as native app. - navigator.mozApps.mgmt.getNotInstalled().onsuccess = function() { + navigator.mozApps.mgmt.getAll().onsuccess = function() { for (i in this.result) { var app = this.result[i]; if (app.manifestURL == gManifestURL) { diff --git a/gfx/docs/index.rst b/gfx/docs/index.rst new file mode 100644 index 0000000000..c6621c81ab --- /dev/null +++ b/gfx/docs/index.rst @@ -0,0 +1,9 @@ +======== +Graphics +======== + +The graphics team's documentation is currently using doxygen. We're tracking the work to integrate it better at https://bugzilla.mozilla.org/show_bug.cgi?id=1150232. + +For now you can read the graphics source code documentation here: + +http://people.mozilla.org/~bgirard/doxygen/gfx/ diff --git a/gfx/moz.build b/gfx/moz.build index ccc9e4a410..2ed70f83a8 100644 --- a/gfx/moz.build +++ b/gfx/moz.build @@ -31,3 +31,4 @@ if CONFIG['ENABLE_TESTS']: TEST_DIRS += ['tests'] +SPHINX_TREES['gfx'] = 'docs' diff --git a/gfx/src/nsFontMetrics.cpp b/gfx/src/nsFontMetrics.cpp index 311d698ab2..9b18e9882d 100644 --- a/gfx/src/nsFontMetrics.cpp +++ b/gfx/src/nsFontMetrics.cpp @@ -81,7 +81,7 @@ private: class StubPropertyProvider : public gfxTextRun::PropertyProvider { public: - virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, + virtual void GetHyphenationBreaks(gfxTextRun::Range aRange, bool* aBreakBefore) { NS_ERROR("This shouldn't be called because we never call BreakAndMeasureText"); } @@ -101,8 +101,7 @@ public: NS_ERROR("This shouldn't be called because we never enable hyphens"); return 60; } - virtual void GetSpacing(uint32_t aStart, uint32_t aLength, - Spacing* aSpacing) { + virtual void GetSpacing(gfxTextRun::Range aRange, Spacing* aSpacing) { NS_ERROR("This shouldn't be called because we never enable spacing"); } }; @@ -325,8 +324,11 @@ nsFontMetrics::GetWidth(const char* aString, uint32_t aLength, StubPropertyProvider provider; AutoTextRun textRun(this, aDrawTarget, aString, aLength); - return textRun.get() ? - NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0; + if (textRun.get()) { + return NSToCoordRound( + textRun->GetAdvanceWidth(Range(0, aLength), &provider)); + } + return 0; } nscoord @@ -341,8 +343,11 @@ nsFontMetrics::GetWidth(const char16_t* aString, uint32_t aLength, StubPropertyProvider provider; AutoTextRun textRun(this, aDrawTarget, aString, aLength); - return textRun.get() ? - NSToCoordRound(textRun->GetAdvanceWidth(0, aLength, &provider)) : 0; + if (textRun.get()) { + return NSToCoordRound( + textRun->GetAdvanceWidth(Range(0, aLength), &provider)); + } + return 0; } // Draw a string using this font handle on the surface passed in. @@ -360,15 +365,17 @@ nsFontMetrics::DrawString(const char *aString, uint32_t aLength, return; } gfxPoint pt(aX, aY); + Range range(0, aLength); if (mTextRunRTL) { if (mVertical) { - pt.y += textRun->GetAdvanceWidth(0, aLength, &provider); + pt.y += textRun->GetAdvanceWidth(range, &provider); } else { - pt.x += textRun->GetAdvanceWidth(0, aLength, &provider); + pt.x += textRun->GetAdvanceWidth(range, &provider); } } - textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength, - &provider, nullptr, nullptr); + gfxTextRun::DrawParams params(aContext->ThebesContext()); + params.provider = &provider; + textRun->Draw(range, pt, params); } void @@ -386,15 +393,17 @@ nsFontMetrics::DrawString(const char16_t* aString, uint32_t aLength, return; } gfxPoint pt(aX, aY); + Range range(0, aLength); if (mTextRunRTL) { if (mVertical) { - pt.y += textRun->GetAdvanceWidth(0, aLength, &provider); + pt.y += textRun->GetAdvanceWidth(range, &provider); } else { - pt.x += textRun->GetAdvanceWidth(0, aLength, &provider); + pt.x += textRun->GetAdvanceWidth(range, &provider); } } - textRun->Draw(aContext->ThebesContext(), pt, DrawMode::GLYPH_FILL, 0, aLength, - &provider, nullptr, nullptr); + gfxTextRun::DrawParams params(aContext->ThebesContext()); + params.provider = &provider; + textRun->Draw(range, pt, params); } static nsBoundingMetrics @@ -409,8 +418,8 @@ GetTextBoundingMetrics(nsFontMetrics* aMetrics, const char16_t* aString, AutoTextRun textRun(aMetrics, aDrawTarget, aString, aLength); nsBoundingMetrics m; if (textRun.get()) { - gfxTextRun::Metrics theMetrics = - textRun->MeasureText(0, aLength, aType, aDrawTarget, &provider); + gfxTextRun::Metrics theMetrics = textRun->MeasureText( + gfxTextRun::Range(0, aLength), aType, aDrawTarget, &provider); m.leftBearing = NSToCoordFloor( theMetrics.mBoundingBox.X()); m.rightBearing = NSToCoordCeil( theMetrics.mBoundingBox.XMost()); diff --git a/gfx/src/nsFontMetrics.h b/gfx/src/nsFontMetrics.h index cecdf103f7..0c38818f8b 100644 --- a/gfx/src/nsFontMetrics.h +++ b/gfx/src/nsFontMetrics.h @@ -46,6 +46,7 @@ struct nsBoundingMetrics; class nsFontMetrics final { public: + typedef gfxTextRun::Range Range; typedef mozilla::gfx::DrawTarget DrawTarget; nsFontMetrics(); diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp index 22045569ac..2594a6a322 100644 --- a/gfx/thebes/gfxDWriteFonts.cpp +++ b/gfx/thebes/gfxDWriteFonts.cpp @@ -546,8 +546,6 @@ gfxDWriteFont::GetCairoScaledFont() cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont, mAllowManualShowGlyphs); - gfxDWriteFontEntry *fe = - static_cast(mFontEntry.get()); cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont, GetForceGDIClassic()); } diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index eea018aee1..8413496c63 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -184,132 +184,6 @@ MapFcWidth(int aFcWidth) return NS_FONT_STRETCH_ULTRA_EXPANDED; } -// mapping of moz lang groups ==> default lang -struct MozLangGroupData { - nsIAtom* const& mozLangGroup; - const char *defaultLang; -}; - -const MozLangGroupData MozLangGroups[] = { - { nsGkAtoms::x_western, "en" }, - { nsGkAtoms::x_cyrillic, "ru" }, - { nsGkAtoms::x_devanagari, "hi" }, - { nsGkAtoms::x_tamil, "ta" }, - { nsGkAtoms::x_armn, "hy" }, - { nsGkAtoms::x_beng, "bn" }, - { nsGkAtoms::x_cans, "iu" }, - { nsGkAtoms::x_ethi, "am" }, - { nsGkAtoms::x_geor, "ka" }, - { nsGkAtoms::x_gujr, "gu" }, - { nsGkAtoms::x_guru, "pa" }, - { nsGkAtoms::x_khmr, "km" }, - { nsGkAtoms::x_knda, "kn" }, - { nsGkAtoms::x_mlym, "ml" }, - { nsGkAtoms::x_orya, "or" }, - { nsGkAtoms::x_sinh, "si" }, - { nsGkAtoms::x_tamil, "ta" }, - { nsGkAtoms::x_telu, "te" }, - { nsGkAtoms::x_tibt, "bo" }, - { nsGkAtoms::Unicode, 0 } -}; - -bool -gfxFcPlatformFontList::TryLangForGroup(const nsACString& aOSLang, - nsIAtom* aLangGroup, - nsACString& aFcLang) -{ - // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. - // aOSLang is in the form "language[_territory][.codeset][@modifier]". - // fontconfig takes languages in the form "language-territory". - // nsILanguageAtomService takes languages in the form language-subtag, - // where subtag may be a territory. fontconfig and nsILanguageAtomService - // handle case-conversion for us. - const char *pos, *end; - aOSLang.BeginReading(pos); - aOSLang.EndReading(end); - aFcLang.Truncate(); - while (pos < end) { - switch (*pos) { - case '.': - case '@': - end = pos; - break; - case '_': - aFcLang.Append('-'); - break; - default: - aFcLang.Append(*pos); - } - ++pos; - } - - nsILanguageAtomService* langService = GetLangService(); - nsIAtom *atom = langService->LookupLanguage(aFcLang); - return atom == aLangGroup; -} - -void -gfxFcPlatformFontList::GetSampleLangForGroup(nsIAtom* aLanguage, - nsACString& aLangStr) -{ - aLangStr.Truncate(); - if (!aLanguage) { - return; - } - - // set up lang string - const MozLangGroupData *mozLangGroup = nullptr; - - // -- look it up in the list of moz lang groups - for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) { - if (aLanguage == MozLangGroups[i].mozLangGroup) { - mozLangGroup = &MozLangGroups[i]; - break; - } - } - - // -- not a mozilla lang group? Just return the BCP47 string - // representation of the lang group - if (!mozLangGroup) { - // Not a special mozilla language group. - // Use aLanguage as a language code. - aLanguage->ToUTF8String(aLangStr); - return; - } - - // -- check the environment for the user's preferred language that - // corresponds to this mozilla lang group. - const char *languages = getenv("LANGUAGE"); - if (languages) { - const char separator = ':'; - - for (const char *pos = languages; true; ++pos) { - if (*pos == '\0' || *pos == separator) { - if (languages < pos && - TryLangForGroup(Substring(languages, pos), - aLanguage, aLangStr)) - return; - - if (*pos == '\0') - break; - - languages = pos + 1; - } - } - } - const char *ctype = setlocale(LC_CTYPE, nullptr); - if (ctype && - TryLangForGroup(nsDependentCString(ctype), aLanguage, aLangStr)) { - return; - } - - if (mozLangGroup->defaultLang) { - aLangStr.Assign(mozLangGroup->defaultLang); - } else { - aLangStr.Truncate(); - } -} - gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName, FcPattern* aFontPattern) : gfxFontEntry(aFaceName), mFontPattern(aFontPattern), diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 6cedc9bd4e..8873a59093 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -245,8 +245,6 @@ public: mGenericMappings.Clear(); } - void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr); - static FT_Library GetFTLibrary(); protected: @@ -263,10 +261,6 @@ protected: // are all pref font settings set to use fontconfig generics? bool PrefFontListsUseOnlyGenerics(); - // helper method for finding an appropriate fontconfig language - bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup, - nsACString& aFcLang); - static void CheckFontUpdates(nsITimer *aTimer, void *aThis); #ifdef MOZ_BUNDLED_FONTS diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 44f51d6a42..2ba4522b96 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1943,7 +1943,8 @@ gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt, const EmphasisMarkDrawParams& aParams) { gfxFloat& inlineCoord = aParams.isVertical ? aPt->y : aPt->x; - uint32_t markLength = aParams.mark->GetLength(); + gfxTextRun::Range markRange(aParams.mark); + gfxTextRun::DrawParams params(aParams.context); gfxFloat clusterStart = -std::numeric_limits::infinity(); bool shouldDrawEmphasisMark = false; @@ -1965,8 +1966,7 @@ gfxFont::DrawEmphasisMarks(gfxTextRun* aShapedText, gfxPoint* aPt, // Move the coord backward to get the needed start point. gfxFloat delta = (clusterAdvance + aParams.advance) / 2; inlineCoord -= delta; - aParams.mark->Draw(aParams.context, *aPt, DrawMode::GLYPH_FILL, - 0, markLength, nullptr, nullptr, nullptr); + aParams.mark->Draw(markRange, *aPt, params); inlineCoord += delta; shouldDrawEmphasisMark = false; } @@ -3198,7 +3198,8 @@ gfxFont::InitFakeSmallCapsRun(DrawTarget *aDrawTarget, MergeCharactersInTextRun(mergedRun, tempRun, charsToMergeArray.Elements(), deletedCharsArray.Elements()); - aTextRun->CopyGlyphDataFrom(mergedRun, 0, runLength, + gfxTextRun::Range runRange(0, runLength); + aTextRun->CopyGlyphDataFrom(mergedRun, runRange, aOffset + runStart); } } else { diff --git a/gfx/thebes/gfxFontUtils.cpp b/gfx/thebes/gfxFontUtils.cpp index 6b7b0ef9fb..af7b896a10 100644 --- a/gfx/thebes/gfxFontUtils.cpp +++ b/gfx/thebes/gfxFontUtils.cpp @@ -388,7 +388,7 @@ gfxFontUtils::ReadCMAPTableFormat14(const uint8_t *aBuf, uint32_t aLength, #define acceptableUCS4Encoding(p, e, k) \ (((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDUCS4ForMicrosoftPlatform) && (k) != 12 || \ ((p) == PLATFORM_ID_UNICODE && \ - ((e) == EncodingIDDefaultForUnicodePlatform || (e) >= EncodingIDUCS4ForUnicodePlatform))) + ((e) != EncodingIDUVSForUnicodePlatform))) #else #define acceptableFormat4(p,e,k) ((p) == PLATFORM_ID_MICROSOFT && (e) == EncodingIDMicrosoft) @@ -960,19 +960,19 @@ gfxFontUtils::DetermineFontDataType(const uint8_t *aFontData, uint32_t aFontData return GFX_USERFONT_UNKNOWN; } -/* static */ -TableDirEntry* -gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag) -{ - const SFNTHeader* header = - reinterpret_cast(aFontData); - const TableDirEntry* dir = - reinterpret_cast(header + 1); - return static_cast - (bsearch(&aTableTag, dir, uint16_t(header->numTables), - sizeof(TableDirEntry), DirEntryCmp)); -} - +/* static */ +TableDirEntry* +gfxFontUtils::FindTableDirEntry(const void* aFontData, uint32_t aTableTag) +{ + const SFNTHeader* header = + reinterpret_cast(aFontData); + const TableDirEntry* dir = + reinterpret_cast(header + 1); + return static_cast + (bsearch(&aTableTag, dir, uint16_t(header->numTables), + sizeof(TableDirEntry), DirEntryCmp)); +} + nsresult gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData, @@ -1057,9 +1057,9 @@ gfxFontUtils::RenameFont(const nsAString& aName, const uint8_t *aFontData, SFNTHeader *sfntHeader = reinterpret_cast(newFontData); // table directory entries begin immediately following SFNT header - TableDirEntry *dirEntry = - FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e')); - // function only called if font validates, so this should always be true + TableDirEntry *dirEntry = + FindTableDirEntry(newFontData, TRUETYPE_TAG('n','a','m','e')); + // function only called if font validates, so this should always be true MOZ_ASSERT(dirEntry, "attempt to rename font with no name table"); uint32_t numTables = sfntHeader->numTables; diff --git a/gfx/thebes/gfxFontUtils.h b/gfx/thebes/gfxFontUtils.h index bbda813660..816a570150 100644 --- a/gfx/thebes/gfxFontUtils.h +++ b/gfx/thebes/gfxFontUtils.h @@ -98,7 +98,6 @@ public: bool hasBlocksInRange = false; endBlock = aEnd >> BLOCK_INDEX_SHIFT; - blockIndex = startBlock; for (blockIndex = startBlock; blockIndex <= endBlock; blockIndex++) { if (blockIndex < blockLen && mBlocks[blockIndex]) hasBlocksInRange = true; @@ -856,18 +855,18 @@ public: GetFamilyNameFromTable(hb_blob_t *aNameTable, nsAString& aFamilyName); - // Find the table directory entry for a given table tag, in a (validated) - // buffer of 'sfnt' data. Returns null if the tag is not present. - static mozilla::TableDirEntry* - FindTableDirEntry(const void* aFontData, uint32_t aTableTag); - - // Return a blob that wraps a table found within a buffer of font data. - // The blob does NOT own its data; caller guarantees that the buffer - // will remain valid at least as long as the blob. - // Returns null if the specified table is not found. - // This method assumes aFontData is valid 'sfnt' data; before using this, - // caller is responsible to do any sanitization/validation necessary. - static hb_blob_t* + // Find the table directory entry for a given table tag, in a (validated) + // buffer of 'sfnt' data. Returns null if the tag is not present. + static mozilla::TableDirEntry* + FindTableDirEntry(const void* aFontData, uint32_t aTableTag); + + // Return a blob that wraps a table found within a buffer of font data. + // The blob does NOT own its data; caller guarantees that the buffer + // will remain valid at least as long as the blob. + // Returns null if the specified table is not found. + // This method assumes aFontData is valid 'sfnt' data; before using this, + // caller is responsible to do any sanitization/validation necessary. + static hb_blob_t* GetTableFromFontData(const void* aFontData, uint32_t aTableTag); // create a new name table and build a new font with that name table diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp index 2ccb6897f4..acd77318e6 100644 --- a/gfx/thebes/gfxFontconfigFonts.cpp +++ b/gfx/thebes/gfxFontconfigFonts.cpp @@ -1625,9 +1625,14 @@ gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, nextFont = 1; } - // Pango, GLib, and Thebes (but not harfbuzz!) all happen to use the same - // script codes, so we can just cast the value here. - const PangoScript script = static_cast(aRunScript); + // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values + // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag. + // Note that PangoScript is defined to be compatible with GUnicodeScript: + // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript + const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript); + const PangoScript script = + (const PangoScript)g_unicode_script_from_iso15924(scriptTag); + // Might be nice to call pango_language_includes_script only once for the // run rather than for each character. PangoLanguage *scriptLang; @@ -1654,19 +1659,6 @@ gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, return nullptr; } -// Sanity-check: spot-check a few constants to confirm that Thebes and -// Pango script codes really do match -#define CHECK_SCRIPT_CODE(script) \ - PR_STATIC_ASSERT(int32_t(MOZ_SCRIPT_##script) == \ - int32_t(PANGO_SCRIPT_##script)) - -CHECK_SCRIPT_CODE(COMMON); -CHECK_SCRIPT_CODE(INHERITED); -CHECK_SCRIPT_CODE(ARABIC); -CHECK_SCRIPT_CODE(LATIN); -CHECK_SCRIPT_CODE(UNKNOWN); -CHECK_SCRIPT_CODE(NKO); - /** ** gfxFcFont **/ diff --git a/gfx/thebes/gfxHarfBuzzShaper.cpp b/gfx/thebes/gfxHarfBuzzShaper.cpp index a8307543ba..3fd195c2f2 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -354,17 +354,6 @@ gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t *font, void *font_data, return fcd->mShaper->GetGlyphVAdvance(glyph); } -/* static */ -hb_bool_t -gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, - void *user_data) -{ - // We work in horizontal coordinates, so no origin adjustment needed here. - return true; -} - struct VORG { AutoSwap_PRUint16 majorVersion; AutoSwap_PRUint16 minorVersion; @@ -1267,9 +1256,6 @@ gfxHarfBuzzShaper::Initialize() hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs, HBGetGlyphVAdvance, nullptr, nullptr); - hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs, - HBGetGlyphHOrigin, - nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs, HBGetGlyphVOrigin, nullptr, nullptr); diff --git a/gfx/thebes/gfxHarfBuzzShaper.h b/gfx/thebes/gfxHarfBuzzShaper.h index 122dec4a34..7171171562 100644 --- a/gfx/thebes/gfxHarfBuzzShaper.h +++ b/gfx/thebes/gfxHarfBuzzShaper.h @@ -61,11 +61,6 @@ public: hb_codepoint_t glyph, void *user_data); static hb_bool_t - HBGetGlyphHOrigin(hb_font_t *font, void *font_data, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y, - void *user_data); - static hb_bool_t HBGetGlyphVOrigin(hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 766a4c08e4..7a09542c74 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -6,7 +6,11 @@ #ifndef gfxMacPlatformFontList_H_ #define gfxMacPlatformFontList_H_ +#include #include +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +#include +#endif #include "mozilla/MemoryReporting.h" #include "nsDataHashtable.h" @@ -32,13 +36,34 @@ public: bool aIsStandardFace = false); // for use with data fonts +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef, +#else + MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef, +#endif uint16_t aWeight, uint16_t aStretch, uint8_t aStyle, +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + ATSFontContainerRef aContainerRef, // 10.4Fx +#endif bool aIsDataUserFont, bool aIsLocal); virtual ~MacOSFontEntry() { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) ::CGFontRelease(mFontRef); +#else + if (mFontRefInitialized) + ::CGFontRelease(mFontRef); + /* Per Apple, even synthesized CGFontRefs must be released. Also, + we do need to release our container ref, if any. */ + if (mContainerRef) + ::ATSFontDeactivate(mContainerRef, NULL, + kATSOptionFlagsDefault); +#endif } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + // 10.4Fx + ATSFontRef GetATSFontRef(); +#endif virtual CGFontRef GetFontRef(); @@ -63,7 +88,15 @@ protected: static void DestroyBlobFunc(void* aUserData); CGFontRef mFontRef; // owning reference to the CGFont, released on destruction - +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + // 10.4Fx class variables + ATSFontRef mATSFontRef; // 10.4Fx (owning reference to our ATSFont) + ATSFontContainerRef mContainerRef; // 10.4Fx (for MakePlatformFont) + bool mATSFontRefInitialized; // 10.4Fx. mUserFontData is in gfxFont.h. + AutoTArray mFontTableDir; // 10.4Fx + ByteCount mFontTableDirSize; // 10.4Fx + void TryGlobalFontTableCache(); +#endif bool mFontRefInitialized; bool mRequiresAAT; bool mIsCFF; @@ -124,11 +157,21 @@ private: // helper function to lookup in both hidden system fonts and normal fonts gfxFontFamily* FindSystemFontFamily(const nsAString& aFamily); +#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo); +#else + // eliminate faces which have the same ATS font reference + // backout bug 663688 + void EliminateDuplicateFaces(const nsAString& aFamilyName); + + // backout bug 869762 + static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg); + uint32_t mATSGeneration; +#endif // search fonts system-wide for a given character, null otherwise gfxFontEntry* GlobalFontFallback(const uint32_t aCh, diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 75fe3efeed..573eb6c892 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -69,6 +69,7 @@ #include #include +#include using namespace mozilla; @@ -278,14 +279,27 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, mRequiresAAT(false), mIsCFF(false), mIsCFFInitialized(false) +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + , mATSFontRef(kInvalidFont), + mFontTableDirSize(0), + mContainerRef(NULL), + mATSFontRefInitialized(false) /* 10.4Fx */ +#endif // 10.5 { mWeight = aWeight; } MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) CGFontRef aFontRef, +#else + ATSFontRef aFontRef, // 10.4Fx +#endif uint16_t aWeight, uint16_t aStretch, uint8_t aStyle, +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + ATSFontContainerRef aContainerRef, // 10.4Fx +#endif bool aIsDataUserFont, bool aIsLocalUserFont) : gfxFontEntry(aPostscriptName, false), @@ -295,9 +309,18 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, mIsCFF(false), mIsCFFInitialized(false) { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) mFontRef = aFontRef; mFontRefInitialized = true; ::CFRetain(mFontRef); +#else + // ATSFontRef version + // We don't retain mFontRef here because we synthesize it. + mATSFontRef = aFontRef; + mATSFontRefInitialized = true; // keep mFontRef as if not initialized + mContainerRef = aContainerRef; + mFontTableDirSize = 0; +#endif mWeight = aWeight; mStretch = aStretch; @@ -310,6 +333,7 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, mIsLocalUserFont = aIsLocalUserFont; } +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) CGFontRef MacOSFontEntry::GetFontRef() { @@ -320,6 +344,39 @@ MacOSFontEntry::GetFontRef() } return mFontRef; } +#else +/* Define ATSFontRef and CGFontRef getters for 10.4/5. */ +ATSFontRef +MacOSFontEntry::GetATSFontRef() +{ + if (!mATSFontRefInitialized) { + mATSFontRefInitialized = true; + NSString *psname = GetNSStringForString(mName); + mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname), + kATSOptionFlagsDefault); + } + return mATSFontRef; +} +CGFontRef +MacOSFontEntry::GetFontRef() +{ + if (mFontRefInitialized) { + return mFontRef; + } + + // GetATSFontRef will initialize mATSFontRef + if (GetATSFontRef() == kInvalidFont) { + return nullptr; + } + + mFontRef = ::CGFontCreateWithPlatformFont(&mATSFontRef); + // Per Apple, we need to release this later with CGFontRelease. See +// https://developer.apple.com/library/mac/documentation/graphicsimaging/reference/CGFont/DeprecationAppendix/AppendixADeprecatedAPI.html + mFontRefInitialized = true; + + return mFontRef; +} +#endif // 10.6 and up // For a logging build, we wrap the CFDataRef in a FontTableRec so that we can // use the MOZ_COUNT_[CD]TOR macros in it. A release build without logging @@ -352,9 +409,34 @@ MacOSFontEntry::DestroyBlobFunc(void* aUserData) #endif } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// It is possible for multiple entries to be instantiated that have no clue +// of each other, making us reload this font multiple times (usually kicked +// off by gfxTextRun). Accelerating webfonts is generally pointless, but for +// platform fonts, we can cache the directory globally in the platform +// object and save substantial time. +void +MacOSFontEntry::TryGlobalFontTableCache() +{ + if (mFontTableDirSize) return; + + ByteCount trys = reinterpret_cast( + gfxPlatform::GetPlatform())->GetCachedDirSizeForFont(mName); + if (!trys) return; + uint8_t *x = reinterpret_cast( + gfxPlatform::GetPlatform())->GetCachedDirForFont(mName); + if (!x) return; + mFontTableDirSize = trys; + mFontTableDir.SetLength(trys, fallible); + memcpy(mFontTableDir.Elements(), x, trys); + return; +} +#endif + hb_blob_t * MacOSFontEntry::GetFontTable(uint32_t aTag) { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) CGFontRef fontRef = GetFontRef(); if (!fontRef) { return nullptr; @@ -374,11 +456,139 @@ MacOSFontEntry::GetFontTable(uint32_t aTag) } return nullptr; +#else // 10.5 + // ATSFontRef version + // This is based on the high probability we called HasFontTable() before + // we called this to actually get it; HasFontTable() will cache the + // directory for us. + nsAutoreleasePool localPool; + + ATSFontRef fontRef = GetATSFontRef(); + if (fontRef == kInvalidFont) return nullptr; + + ByteCount dataLength = 0; + + if (!mIsDataUserFont || mIsLocalUserFont) TryGlobalFontTableCache(); + + // See if we already know how long the table is. This saves a potentially + // expensive call to ATSGetFontTable() to simply get the length. + // Essentially a hardcoded form of FindTagInTableDir; see below. + if (MOZ_LIKELY(mFontTableDirSize > 0)) { + uint32_t aTagHE = aTag; +#ifndef __ppc__ + aTagHE = __builtin_bswap32(aTag); +#endif + +#ifdef DEBUG_X + uint32_t j = 12; + uint8_t *table = (reinterpret_cast( + mFontTableDir.Elements())); + fprintf(stderr, "fast fetch "); +#endif + uint32_t i; + uint32_t *wtable = (reinterpret_cast( + mFontTableDir.Elements())); + + for (i=3; i<(mFontTableDirSize/4); i+=4) { // Skip header +#ifdef DEBUG_X + char tag[5] = { table[j], table[j+1], table[j+2], table[j+3], + '\0' }; + fprintf(stderr, "%s ", tag); // remember: host endian + j += 16; +#endif + // ASSUME THAT aTag is in host endianness + if(wtable[i] == aTagHE) { + dataLength = (ByteCount)wtable[i+3]; +#ifndef __ppc__ + dataLength = __builtin_bswap32(dataLength); +#endif +#ifdef DEBUG_X + fprintf(stderr, "FF MATCH: length %u\n", dataLength); +#endif + break; + } + } + } + + if (MOZ_UNLIKELY(dataLength == 0)) { + // Either we don't know, or something was wrong with the table. +#ifdef DEBUG_X + if (mFontTableDirSize > 0) fprintf(stderr, "NO MATCH\n"); +#endif + OSStatus status = ::ATSFontGetTable(fontRef, aTag, 0, 0, 0, + &dataLength); + if (MOZ_UNLIKELY(status != noErr)) return nullptr; + } + + // Taking advantage of bridging CFMutableDataRef to CFDataRef. + CFMutableDataRef dataRef = ::CFDataCreateMutable(kCFAllocatorDefault, + dataLength); + if (!dataRef) return nullptr; + + ::CFDataIncreaseLength(dataRef, dataLength); // paranoia + if(MOZ_UNLIKELY(::ATSFontGetTable(fontRef, aTag, 0, dataLength, + ::CFDataGetMutableBytePtr(dataRef), + &dataLength) != noErr)) { + ::CFRelease(dataRef); + return nullptr; + } + + return hb_blob_create((const char*)::CFDataGetBytePtr(dataRef), + ::CFDataGetLength(dataRef), + HB_MEMORY_MODE_READONLY, +#ifdef NS_BUILD_REFCNT_LOGGING + new FontTableRec(dataRef), +#else + (void*)dataRef, +#endif + DestroyBlobFunc); +#endif // 10.6 and up } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +static bool FindTagInTableDir(nsTArray& table, + uint32_t aTableTag, ByteCount sizer) { + // Parse it. In big endian format, each entry is 4 32-bit words + // corresponding to the tag, checksum, offset and length, with a + // 96 bit header (three 32-bit words). One day we could even write + // an AltiVec version ... + // aTableTag is expected to be Big Endian order +#ifndef __ppc__ + aTableTag = __builtin_bswap32(aTableTag); +#endif + +#ifdef DEBUG_X + fprintf(stderr, "Tables: "); + uint32_t j = 12; +#endif + uint32_t i; + uint32_t *wtable = (reinterpret_cast(table.Elements())); + for (i=3; i<(sizer/4); i+=4) { // Skip header +#ifdef DEBUG_X + char tag[5] = { table[j], table[j+1], table[j+2], table[j+3], '\0' }; + fprintf(stderr, "%s ", tag); // remember: big endian + j+=16; +#endif + // ASSUME THAT aTableTag is already big endian (we converted it in case) + if(wtable[i] == aTableTag) { +#ifdef DEBUG_X + fprintf(stderr, "MATCH\n"); +#endif + return true; + } + } + // Hmmm. Either something is wrong, or there is no table. So no table. +#ifdef DEBUG_X + fprintf(stderr, "NO MATCH\n"); +#endif + return false; +} +#endif // 10.5 + bool MacOSFontEntry::HasFontTable(uint32_t aTableTag) { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) if (mAvailableTables.Count() == 0) { nsAutoreleasePool localPool; @@ -399,6 +609,53 @@ MacOSFontEntry::HasFontTable(uint32_t aTableTag) } return mAvailableTables.GetEntry(aTableTag); +#else + // ATSFontRef version + // This is higher performance than the previous version. + + ATSFontRef fontRef = GetATSFontRef(); + if (fontRef == kInvalidFont) return false; + + if (!mIsDataUserFont || mIsLocalUserFont) TryGlobalFontTableCache(); + + // Use cached directory to avoid repeatedly fetching the same data. + if (MOZ_LIKELY(mFontTableDirSize > 0)) + return FindTagInTableDir(mFontTableDir, aTableTag, mFontTableDirSize); + + ByteCount sizer; + + if(MOZ_LIKELY(::ATSFontGetTableDirectory(fontRef, 0, NULL, &sizer) == noErr)) { + // If the header is abnormal, try the old, slower way in case this + // is a gap in our algorithm. + if (MOZ_UNLIKELY(sizer <= 12 || ((sizer-12) % 16) || sizer >= 1024)) { + fprintf(stderr, "Warning: TenFourFox found " + "abnormal font table dir in %s (%i).\n", + NS_ConvertUTF16toUTF8(mName).get(), sizer); + return + (::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &sizer) == noErr); + } + + // Get and cache the font table directory. + mFontTableDirSize = sizer; + mFontTableDir.SetLength(mFontTableDirSize, fallible); + +#ifdef DEBUG + fprintf(stderr, "Size of %s font table directory: %i\n", + NS_ConvertUTF16toUTF8(mName).get(), mFontTableDir.Length()); +#endif + if (MOZ_LIKELY(::ATSFontGetTableDirectory(fontRef, mFontTableDirSize, + reinterpret_cast(mFontTableDir.Elements()), &sizer) == noErr)) { + + // Push to platform. + if (!mIsDataUserFont || mIsLocalUserFont) + reinterpret_cast(gfxPlatform::GetPlatform())->SetCachedDirForFont(mName, reinterpret_cast(mFontTableDir.Elements()), mFontTableDirSize); + + return FindTagInTableDir(mFontTableDir, aTableTag, mFontTableDirSize); + } + } + mFontTableDirSize = 0; + return nullptr; +#endif // 10.6 and up } void @@ -424,6 +681,11 @@ public: virtual void LocalizedName(nsAString& aLocalizedName); virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr); + +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + + void EliminateDuplicateFaces(); // needed for 10.4 +#endif }; void @@ -569,6 +831,58 @@ gfxMacFontFamily::FindStyleVariations(FontInfoData *aFontInfoData) } } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// restored from bug 663688 for 10.4 +void +gfxMacFontFamily::EliminateDuplicateFaces() +{ + uint32_t i, bold, numFonts, italicIndex; + MacOSFontEntry *italic, *nonitalic; + + FindStyleVariations(); + + // if normal and italic have the same ATS font ref, delete italic + // if bold and bold-italic have the same ATS font ref, delete bold-italic + + // two iterations, one for normal, one for bold + for (bold = 0; bold < 2; bold++) { + numFonts = mAvailableFonts.Length(); + + // find the non-italic face + nonitalic = nullptr; + for (i = 0; i < numFonts; i++) { + if ((mAvailableFonts[i]->IsBold() == (bold == 1)) && + !mAvailableFonts[i]->IsItalic()) { + nonitalic = static_cast(mAvailableFonts[i].get()); + break; + } + } + + // find the italic face + if (nonitalic) { + italic = nullptr; + for (i = 0; i < numFonts; i++) { + if ((mAvailableFonts[i]->IsBold() == (bold == 1)) && + mAvailableFonts[i]->IsItalic()) { + italic = static_cast(mAvailableFonts[i].get()); + italicIndex = i; + break; + } + } + + // if italic face and non-italic face have matching ATS refs, + // or if the italic returns 0 rather than an actual ATSFontRef, + // then the italic face is bogus so remove it + if (italic && (italic->GetATSFontRef() == 0 || + italic->GetATSFontRef() == kInvalidFont || + italic->GetATSFontRef() == nonitalic->GetATSFontRef())) { + mAvailableFonts.RemoveElementAt(italicIndex); + } + } + } +} +#endif // 10.5 only + /* gfxSingleFaceMacFontFamily */ #pragma mark- @@ -645,19 +959,31 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF gfxMacPlatformFontList::gfxMacPlatformFontList() : gfxPlatformFontList(false), +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) mDefaultFont(nullptr), +#else + mDefaultFont(NULL), // we can't use nullptr for an ATSFontRef + mATSGeneration(uint32_t(kATSGenerationInitial)), // backout bug 869762 +#endif mUseSizeSensitiveSystemFont(false) { #ifdef MOZ_BUNDLED_FONTS ActivateBundledFonts(); #endif +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) ::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(), this, RegisteredFontsChangedNotificationCallback, kCTFontManagerRegisteredFontsChangedNotification, 0, CFNotificationSuspensionBehaviorDeliverImmediately); +#else + // backout bug 869762 + ::ATSFontNotificationSubscribe(ATSNotification, + kATSFontNotifyOptionDefault, + (void*)this, nullptr); +#endif // 10.6 and up // cache this in a static variable so that MacOSFontFamily objects // don't have to repeatedly look it up @@ -678,9 +1004,11 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() : gfxMacPlatformFontList::~gfxMacPlatformFontList() { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) if (mDefaultFont) { ::CFRelease(mDefaultFont); } +#endif // 10.6 and up } void @@ -714,6 +1042,8 @@ gfxMacPlatformFontList::AddFamily(CFStringRef aFamily) } } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +#endif nsresult gfxMacPlatformFontList::InitFontList() { @@ -721,10 +1051,21 @@ gfxMacPlatformFontList::InitFontList() Telemetry::AutoTimer timer; +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// backout bug 869762 + ATSGeneration currentGeneration = ::ATSGetGeneration(); + + // need to ignore notifications after adding each font + if (mATSGeneration == currentGeneration) + return NS_OK; + mATSGeneration = currentGeneration; +#endif + // reset font lists gfxPlatformFontList::InitFontList(); mSystemFontFamilies.Clear(); +#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) // iterate over available families CFArrayRef familyNames = CTFontManagerCopyAvailableFontFamilyNames(); @@ -734,6 +1075,32 @@ gfxMacPlatformFontList::InitFontList() } CFRelease(familyNames); +#else + // Pre-Core Text version. + // XXX Currently we don't populate mSystemFontFamilies. + + NSEnumerator *families = [[sFontManager availableFontFamilies] + objectEnumerator]; + // returns "canonical", non-localized family name + + nsAutoString availableFamilyName; + NSString *availableFamily = nil; + while ((availableFamily = [families nextObject])) { + // make a nsString + nsCocoaUtils::GetStringForNSString(availableFamily, availableFamilyName); + // create a family entry + gfxFontFamily *familyEntry = new gfxMacFontFamily(availableFamilyName); + if (!familyEntry) break; + + // add the family entry to the hash table + ToLowerCase(availableFamilyName); + mFontFamilies.Put(availableFamilyName, familyEntry); + + // check the bad underline blacklist + if (mBadUnderlineFamilyNames.Contains(availableFamilyName)) + familyEntry->SetBadUnderlineFamily(); + } +#endif InitSingleFaceList(); @@ -829,8 +1196,8 @@ gfxMacPlatformFontList::InitSystemFonts() // display font family, if on OSX 10.11 if (mUseSizeSensitiveSystemFont) { - sys = [NSFont systemFontOfSize: 128.0]; - NSString* displayFamilyName = GetRealFamilyName(sys); + NSFont* displaySys = [NSFont systemFontOfSize: 128.0]; + NSString* displayFamilyName = GetRealFamilyName(displaySys); nsCocoaUtils::GetStringForNSString(displayFamilyName, familyName); mSystemDisplayFontFamily = FindSystemFontFamily(familyName); NS_ASSERTION(mSystemDisplayFontFamily, "null system display font family"); @@ -848,7 +1215,6 @@ gfxMacPlatformFontList::InitSystemFonts() "system text/display font size switch point is not as expected!"); #endif } - } gfxFontFamily* @@ -884,6 +1250,7 @@ gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAStr return false; } +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) void gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center, void *observer, @@ -903,6 +1270,21 @@ gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificatio // modify a preference that will trigger reflow everywhere fl->ForceGlobalReflow(); } +#else +// backout bug 869762 +void +gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo, + void* aUserArg) +{ + gfxMacPlatformFontList* fl = static_cast(aUserArg); + + // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch + fl->UpdateFontList(); + + // modify a preference that will trigger reflow everywhere + fl->ForceGlobalReflow(); +} +#endif gfxFontEntry* gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh, @@ -1033,6 +1415,28 @@ gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName, NSString *faceName = GetNSStringForString(aFontName); MacOSFontEntry *newFontEntry; +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + // ATSFontRef version + + // first lookup a single face based on postscript name + ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName), + kATSOptionFlagsDefault); + // if not found, lookup using full font name + if (fontRef == kInvalidFont) { + fontRef = ::ATSFontFindFromName(CFStringRef(faceName), + kATSOptionFlagsDefault); + if (fontRef == kInvalidFont) { + return nullptr; + } + } + + NS_ASSERTION(aWeight >= 100 && aWeight <= 900, "bogus font weight value!"); + + newFontEntry = + new MacOSFontEntry(aFontName, fontRef, + aWeight, aStretch, + aStyle, NULL, false, true); // we must use NULL +#else // lookup face based on postscript or full name CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName)); if (!fontRef) { @@ -1046,6 +1450,7 @@ gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName, new MacOSFontEntry(aFontName, fontRef, aWeight, aStretch, aStyle, false, true); ::CFRelease(fontRef); +#endif return newFontEntry; } @@ -1055,6 +1460,18 @@ static void ReleaseData(void *info, const void *data, size_t size) NS_Free((void*)data); } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// Backout from bug 811312 (needed for MakePlatformFont) +// grumble, another non-publised Apple API dependency (found in Webkit code) +// activated with this value, font will not be found via system lookup routines +// it can only be used via the created ATSFontRef +// needed to prevent one doc from finding a font used in a separate doc + +enum { + kPrivateATSFontContextPrivate = 3 +}; +#endif + gfxFontEntry* gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName, uint16_t aWeight, @@ -1075,6 +1492,168 @@ gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName, return nullptr; } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) + // ATSFontRef version + OSStatus err; + + // MakePlatformFont is responsible for deleting the font data with NS_Free + // so we set up a stack object to ensure it is freed even if we take an + // early exit + // XXX Is this still needed? If we exit early, we die anyway. + struct FontDataDeleter { + FontDataDeleter(const uint8_t *aFontData) + : mFontData(aFontData) { } + ~FontDataDeleter() { NS_Free((void*)mFontData); } + const uint8_t *mFontData; + }; + FontDataDeleter autoDelete(aFontData); + + ATSFontRef fontRef; + ATSFontContainerRef containerRef; + + // we get occasional failures when multiple fonts are activated in quick succession + // if the ATS font cache is damaged; to work around this, we can retry the activation + const uint32_t kMaxRetries = 3; + uint32_t retryCount = 0; + while (retryCount++ < kMaxRetries) { + err = ::ATSFontActivateFromMemory(const_cast(aFontData), aLength, + kPrivateATSFontContextPrivate, + kATSFontFormatUnspecified, + NULL, + kATSOptionFlagsDoNotNotify, + &containerRef); + mATSGeneration = ::ATSGetGeneration(); + + if (MOZ_UNLIKELY(err != noErr)) { +#if DEBUG + char warnBuf[1024]; + sprintf(warnBuf, "downloaded font error, ATSFontActivateFromMemory err: %d", + int32_t(err)); + NS_WARNING(warnBuf); +#endif + return nullptr; + } + + // ignoring containers with multiple fonts, use the first face only for now + err = ::ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, + &fontRef, NULL); + if (MOZ_UNLIKELY(err != noErr)) { +#if DEBUG + char warnBuf[1024]; + sprintf(warnBuf, "downloaded font error, ATSFontFindFromContainer err: %d", + int32_t(err)); + NS_WARNING(warnBuf); +#endif + ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); + return nullptr; + } + + // now lookup the Postscript name; this may fail if the font cache is bad + OSStatus err; + NSString *psname = NULL; + err = ::ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, (CFStringRef*) (&psname)); + if (MOZ_LIKELY(err == noErr)) { +#if(0) + fprintf(stderr, "Trying: %s.\n", [psname UTF8String]); +#endif + // Check the font blacklist (TenFourFox issue 261). + // Warning: fonts here do NOT properly fall back. Prefer URI blocking + // if we have the option. + if (0 || + [psname isEqualToString:@"prisjakticons"] || + [psname isEqualToString:@"FSEmericWeb-SemiBold"] || + [psname isEqualToString:@"SFProText-Regular"] || + [psname isEqualToString:@"SFProText-Bold"] || + [psname isEqualToString:@"SFProText-Semibold"] || + [psname isEqualToString:@"SFProDisplay-Medium"] || + [psname isEqualToString:@"SFProDisplay-Light"] || + [psname isEqualToString:@".SFNSDisplay-Ultralight"] || + [psname isEqualToString:@".SFNSText-Light"] || + [psname isEqualToString:@".SFNSDisplay-Light"] || + [psname isEqualToString:@".SFNSText-Medium"] || + [psname isEqualToString:@".SFNSDisplay-Medium"] || + 0) { + fprintf(stderr, +"Warning: TenFourFox rejected ATSUI-incompatible web font %s.\n", + [psname UTF8String]); + [psname release]; + ::ATSFontDeactivate(containerRef, NULL, + kATSOptionFlagsDefault); + + // Create a dummy font, since returning nullptr + // doesn't work properly anymore (TenFourFox issue + // 330). + MacOSFontEntry *newFontEntry = + new MacOSFontEntry(uniqueName, + NULL, // not nullptr + aWeight, aStretch, aStyle, + NULL, // not nullptr + true, false); + // Make it "valid with no characters." + newFontEntry->mIsValid = true; + newFontEntry->mCharacterMap = new gfxCharacterMap(); + return newFontEntry; + } + [psname release]; + } else { +#ifdef DEBUG + char warnBuf[1024]; + sprintf(warnBuf, "ATSFontGetPostScriptName err = %d, retries = %d", + (int32_t)err, retryCount); + NS_WARNING(warnBuf); +#endif + ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); + // retry the activation a couple of times if this fails + // (may be a transient failure due to ATS font cache issues) + continue; + } + + // font entry will own the container ref now + // THIS MUST BE A C++ OBJECT, not an nsAutoPtr, or it will not + // live long enough to be instantiated! + MacOSFontEntry *newFontEntry = + new MacOSFontEntry(uniqueName, + fontRef, + aWeight, + aStretch, + aStyle, + containerRef, true, false); + + // if succeeded and font cmap is good, return the new font + if (MOZ_LIKELY(newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP()))) { + return newFontEntry; + } + + // if something is funky about this font, delete immediately +#if DEBUG + char warnBuf[1024]; + sprintf(warnBuf, "downloaded font not loaded properly, removed face"); + NS_WARNING(warnBuf); +#endif + delete newFontEntry; + + // We don't retry from here; the ATS font cache issue would have caused failure earlier + // so if we get here, there's something else bad going on within our font data structures. + // Currently, there should be no way to reach here, as fontentry creation cannot fail + // except by memory allocation failure. + NS_WARNING("invalid font entry for a newly activated font"); + break; + } + + // If we get here, the activation failed (even with possible retries); we can't use this font. + // We can't just return nullptr anymore, so create a dummy font, like we do above. + fprintf(stderr, "Warning: TenFourFox detected ATSUI font failure; aborting font load.\n"); + MacOSFontEntry *newFontEntry = + new MacOSFontEntry(uniqueName, + NULL, // not nullptr + aWeight, aStretch, aStyle, + NULL, // not nullptr + true, false); + // Make it "valid with no characters." + newFontEntry->mIsValid = true; + newFontEntry->mCharacterMap = new gfxCharacterMap(); + return newFontEntry; +#else CGDataProviderRef provider = ::CGDataProviderCreateWithData(nullptr, aFontData, aLength, &ReleaseData); @@ -1102,6 +1681,7 @@ gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName, #endif return nullptr; +#endif } // Webkit code uses a system font meta name, so mimic that here @@ -1219,6 +1799,7 @@ public: virtual void LoadFontFamilyData(const nsAString& aFamilyName); }; +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) void MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) { @@ -1329,6 +1910,137 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) mLoadStats.othernames += otherFamilyNames.Length(); } } +#else +// ATS-based version. +void +MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName) +{ + // ATS does not have the concept of fonts belonging to a family like + // CoreText does, but the list of names we got from [NSFontManager + // availableFontFamilies] may not exactly correspond to an ATS name. + // However, [NSFontManager availableMembersOfFontFamily] will tell us. + +NS_WARNING("LoadFontFamilyData not yet supported, do not call (bug 962440)"); +MOZ_ASSERT(0); + +#if(0) + nsAutoreleasePool bubble_bubble_toil_and_trouble; + NSString *famName = GetNSStringForString(aFamilyName); +// CFStringRef family = CFStringRef(famName); + NSArray *matchingFonts = + [sFontManager availableMembersOfFontFamily:famName]; + int f, numFaces = (int) CFArrayGetCount(matchingFonts); + if(!numFaces) { +#ifdef DEBUG + fprintf(stderr, "no available fonts for family %s\n", + aFamilyName.get()); +#endif + return; + } + + nsTArray otherFamilyNames; + bool hasOtherFamilyNames = true; + + for (f = 0; f < numFaces; f++) { + mLoadStats.fonts++; + + // Each element is an array of arrays: + // (("Times-Roman", "Roman", 5, 4), ... + // corresponding to the full PSName, the weight name, the weight + // and its traits. We only care about the PSName, because now we + // can get an ATSFontRef from that. + NSArray *k = (NSArray *)CFArrayGetValueAtIndex(matchingFonts, f); + if((int)CFArrayGetCount(k) < 2) { // wtf + continue; + } + NSString *psname = (NSString *)CFArrayGetValueAtIndex(k, 0); +#ifdef DEBUG + fprintf(stderr, "Deferred loading: %s", [psname UTF8String]); +#endif + ATSFontRef fontRef = ::ATSFontFindFromPostScriptName( + (CFStringRef)psname, + kATSOptionFlagsDefault); + if (!fontRef) { // wtff +#ifdef DEBUG + fprintf(stderr, "Failed loading: %s", [psname UTF8String]); +#endif + continue; + } + + if (mLoadCmaps) { + // face name (fudge it into char16_t) + CFStringRef faceName = (CFStringRef)psname; + nsAutoTArray buffer; + CFIndex len = CFStringGetLength(faceName); + buffer.SetLength(len+1); + CFStringGetCharacters(faceName, ::CFRangeMake(0, len), + buffer.Elements()); + buffer[len] = 0; + nsAutoString + fontName(reinterpret_cast(buffer.Elements()), + len); + + // load the cmap data + FontFaceData fontData; + +// Replace with one of the ATSFontTable loaders, but this sucks. + //CFDataRef cmapTable = CTFontCopyTable(fontRef, kCTFontTableCmap, + // kCTFontTableOptionNoOptions); + if (cmapTable) { + bool unicodeFont = false, symbolFont = false; // ignored + const uint8_t *cmapData = + (const uint8_t*)CFDataGetBytePtr(cmapTable); + uint32_t cmapLen = CFDataGetLength(cmapTable); + RefPtr charmap = new gfxCharacterMap(); + uint32_t offset; + nsresult rv; + + rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset, + unicodeFont, symbolFont); + if (NS_SUCCEEDED(rv)) { + fontData.mCharacterMap = charmap; + fontData.mUVSOffset = offset; + fontData.mSymbolFont = symbolFont; + mLoadStats.cmaps++; + } + CFRelease(cmapTable); + } + + mFontFaceData.Put(fontName, fontData); + CFRelease(faceName); + } + +#if (0) +// I don't think this is true for ATS fonts. + if (mLoadOtherNames && hasOtherFamilyNames) { + CFDataRef nameTable = CTFontCopyTable(fontRef, kCTFontTableName, + kCTFontTableOptionNoOptions); + if (nameTable) { + const char *nameData = (const char*)CFDataGetBytePtr(nameTable); + uint32_t nameLen = CFDataGetLength(nameTable); + gfxFontFamily::ReadOtherFamilyNamesForFace(aFamilyName, + nameData, nameLen, + otherFamilyNames, + false); + hasOtherFamilyNames = otherFamilyNames.Length() != 0; + CFRelease(nameTable); + } + } + + CFRelease(fontRef); + } +#endif + CFRelease(matchingFonts); + + // if found other names, insert them in the hash table + if (otherFamilyNames.Length() != 0) { + mOtherFamilyNames.Put(aFamilyName, otherFamilyNames); + mLoadStats.othernames += otherFamilyNames.Length(); + } +#endif +} +#endif // 10.6 and up + already_AddRefed gfxMacPlatformFontList::CreateFontInfoData() diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 916ab37e2b..362c24c4aa 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -132,9 +132,15 @@ enum class DeviceResetReason DRIVER_ERROR, INVALID_CALL, OUT_OF_MEMORY, + FORCED_RESET, UNKNOWN }; +enum class ForcedDeviceResetReason +{ + OPENSHAREDHANDLE = 0 +}; + class gfxPlatform { friend class SRGBOverrideObserver; diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index d9d9d94e4a..9ed85639bc 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -25,6 +25,8 @@ #include "mozilla/TimeStamp.h" #include "mozilla/gfx/2D.h" +#include + using namespace mozilla; #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \ @@ -1225,6 +1227,135 @@ gfxPlatformFontList::GetGenericName(FontFamilyType aGenericType) return generic; } +// mapping of moz lang groups ==> default lang +struct MozLangGroupData { + nsIAtom* const& mozLangGroup; + const char *defaultLang; +}; + +const MozLangGroupData MozLangGroups[] = { + { nsGkAtoms::x_western, "en" }, + { nsGkAtoms::x_cyrillic, "ru" }, + { nsGkAtoms::x_devanagari, "hi" }, + { nsGkAtoms::x_tamil, "ta" }, + { nsGkAtoms::x_armn, "hy" }, + { nsGkAtoms::x_beng, "bn" }, + { nsGkAtoms::x_cans, "iu" }, + { nsGkAtoms::x_ethi, "am" }, + { nsGkAtoms::x_geor, "ka" }, + { nsGkAtoms::x_gujr, "gu" }, + { nsGkAtoms::x_guru, "pa" }, + { nsGkAtoms::x_khmr, "km" }, + { nsGkAtoms::x_knda, "kn" }, + { nsGkAtoms::x_mlym, "ml" }, + { nsGkAtoms::x_orya, "or" }, + { nsGkAtoms::x_sinh, "si" }, + { nsGkAtoms::x_tamil, "ta" }, + { nsGkAtoms::x_telu, "te" }, + { nsGkAtoms::x_tibt, "bo" }, + { nsGkAtoms::Unicode, 0 } +}; + +bool +gfxPlatformFontList::TryLangForGroup(const nsACString& aOSLang, + nsIAtom* aLangGroup, + nsACString& aFcLang) +{ + // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. + // aOSLang is in the form "language[_territory][.codeset][@modifier]". + // fontconfig takes languages in the form "language-territory". + // nsILanguageAtomService takes languages in the form language-subtag, + // where subtag may be a territory. fontconfig and nsILanguageAtomService + // handle case-conversion for us. + const char *pos, *end; + aOSLang.BeginReading(pos); + aOSLang.EndReading(end); + aFcLang.Truncate(); + while (pos < end) { + switch (*pos) { + case '.': + case '@': + end = pos; + break; + case '_': + aFcLang.Append('-'); + break; + default: + aFcLang.Append(*pos); + } + ++pos; + } + + nsILanguageAtomService* langService = GetLangService(); + nsIAtom *atom = langService->LookupLanguage(aFcLang); + return atom == aLangGroup; +} + +void +gfxPlatformFontList::GetSampleLangForGroup(nsIAtom* aLanguage, + nsACString& aLangStr, + bool aCheckEnvironment) +{ + aLangStr.Truncate(); + if (!aLanguage) { + return; + } + + // set up lang string + const MozLangGroupData *mozLangGroup = nullptr; + + // -- look it up in the list of moz lang groups + for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) { + if (aLanguage == MozLangGroups[i].mozLangGroup) { + mozLangGroup = &MozLangGroups[i]; + break; + } + } + + // -- not a mozilla lang group? Just return the BCP47 string + // representation of the lang group + if (!mozLangGroup) { + // Not a special mozilla language group. + // Use aLanguage as a language code. + aLanguage->ToUTF8String(aLangStr); + return; + } + + // -- check the environment for the user's preferred language that + // corresponds to this mozilla lang group. + if (aCheckEnvironment) { + const char *languages = getenv("LANGUAGE"); + if (languages) { + const char separator = ':'; + + for (const char *pos = languages; true; ++pos) { + if (*pos == '\0' || *pos == separator) { + if (languages < pos && + TryLangForGroup(Substring(languages, pos), + aLanguage, aLangStr)) + return; + + if (*pos == '\0') + break; + + languages = pos + 1; + } + } + } + const char *ctype = setlocale(LC_CTYPE, nullptr); + if (ctype && + TryLangForGroup(nsDependentCString(ctype), aLanguage, aLangStr)) { + return; + } + } + + if (mozLangGroup->defaultLang) { + aLangStr.Assign(mozLangGroup->defaultLang); + } else { + aLangStr.Truncate(); + } +} + void gfxPlatformFontList::InitLoader() { diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 073c744303..394524eebf 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -237,6 +237,10 @@ public: mozilla::FontFamilyType GetDefaultGeneric(eFontPrefLang aLang); + // map lang group ==> lang string + void GetSampleLangForGroup(nsIAtom* aLanguage, nsACString& aLangStr, + bool aCheckEnvironment = true); + protected: class MemoryReporter final : public nsIMemoryReporter { @@ -315,6 +319,10 @@ protected: // helper function to map lang to lang group nsIAtom* GetLangGroup(nsIAtom* aLanguage); + // helper method for finding an appropriate lang string + bool TryLangForGroup(const nsACString& aOSLang, nsIAtom* aLangGroup, + nsACString& aLang); + static const char* GetGenericName(mozilla::FontFamilyType aGenericType); // gfxFontInfoLoader overrides, used to load in font cmaps diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index bc516e2ee8..f9ab0c6336 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -99,11 +99,38 @@ gfxPlatformMac::gfxPlatformMac() MacIOSurfaceLib::LoadLibrary(); } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) gfxPlatformMac::~gfxPlatformMac() { gfxCoreTextShaper::Shutdown(); } +ByteCount +gfxPlatformMac::GetCachedDirSizeForFont(nsString name) +{ + FontDirWrapper *x = PlatformFontDirCache.Get(name); + if (x) return x->sizer; + return 0; +} +uint8_t* +gfxPlatformMac::GetCachedDirForFont(nsString name) +{ + FontDirWrapper *x = PlatformFontDirCache.Get(name); + if (x) + return x->fontDir; + else + return nullptr; +} +void +gfxPlatformMac::SetCachedDirForFont(nsString name, uint8_t* table, ByteCount sizer) +{ + if (MOZ_UNLIKELY(sizer < 1 || sizer > 1023)) return; + + FontDirWrapper *k = new FontDirWrapper(sizer, table); + PlatformFontDirCache.Put(name, k); +} +#endif + gfxPlatformFontList* gfxPlatformMac::CreatePlatformFontList() { diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h index 0e45eefdb7..1c251e1412 100644 --- a/gfx/thebes/gfxPlatformMac.h +++ b/gfx/thebes/gfxPlatformMac.h @@ -6,10 +6,19 @@ #ifndef GFX_PLATFORM_MAC_H #define GFX_PLATFORM_MAC_H +#include + #include "nsTArrayForwardDeclare.h" #include "gfxPlatform.h" #include "mozilla/LookAndFeel.h" +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +#include "nsDataHashtable.h" +#include "nsClassHashtable.h" + +typedef size_t ByteCount; +#endif + namespace mozilla { namespace gfx { class DrawTarget; @@ -17,6 +26,21 @@ class VsyncSource; } // namespace gfx } // namespace mozilla +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +// 10.4Fx +class FontDirWrapper { +public: + uint8_t fontDir[1024]; + ByteCount sizer; + FontDirWrapper(ByteCount sized, uint8_t *dir) { + if (MOZ_UNLIKELY(sized < 1 || sized > 1023)) return; + sizer = sized; + memcpy(fontDir, dir, sizer); + } + ~FontDirWrapper() { } +}; +#endif + class gfxPlatformMac : public gfxPlatform { public: gfxPlatformMac(); @@ -97,6 +121,13 @@ public: // lower threshold on font anti-aliasing uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) +/* ATS acceleration functions for 10.4 */ +ByteCount GetCachedDirSizeForFont(nsString name); +uint8_t *GetCachedDirForFont(nsString name); +void SetCachedDirForFont(nsString name, uint8_t* table, ByteCount sizer); +nsClassHashtable< nsStringHashKey, FontDirWrapper > PlatformFontDirCache; +#endif protected: bool AccelerateLayersByDefault() override; diff --git a/gfx/thebes/gfxScriptItemizer.cpp b/gfx/thebes/gfxScriptItemizer.cpp index 3339503acd..b6091a0c3f 100644 --- a/gfx/thebes/gfxScriptItemizer.cpp +++ b/gfx/thebes/gfxScriptItemizer.cpp @@ -158,19 +158,11 @@ gfxScriptItemizer::Next(uint32_t& aRunStart, uint32_t& aRunLimit, } } - // Get the nsCharProps2 record for the current character, - // so we can read the script and (if needed) the gen category - // without needing to do two multi-level lookups. - // NOTE that this means we're relying on an implementation detail - // of the nsUnicodeProperties tables, and might have to revise this - // if the nsCharProps records used there are modified in future. - const nsCharProps2& charProps = GetCharProps2(ch); - // Initialize gc to UNASSIGNED; we'll only set it to the true GC // if the character has script=COMMON, otherwise we don't care. uint8_t gc = HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED; - sc = charProps.mScriptCode; + sc = GetScriptCode(ch); if (sc == MOZ_SCRIPT_COMMON) { /* * Paired character handling: @@ -183,7 +175,7 @@ gfxScriptItemizer::Next(uint32_t& aRunStart, uint32_t& aRunLimit, * We only do this if the script is COMMON; for chars with * specific script assignments, we just use them as-is. */ - gc = charProps.mCategory; + GetGeneralCategory(ch); if (gc == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION) { uint32_t endPairChar = mozilla::unicode::GetMirroredChar(ch); if (endPairChar != ch) { diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 694ffb2e9d..a2edd8f5dc 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -210,15 +210,14 @@ gfxTextRun::ReleaseFontGroup() } bool -gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, - uint8_t *aBreakBefore) +gfxTextRun::SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore) { - NS_ASSERTION(aStart + aLength <= GetLength(), "Overflow"); + NS_ASSERTION(aRange.end <= GetLength(), "Overflow"); uint32_t changed = 0; uint32_t i; - CompressedGlyph *charGlyphs = mCharacterGlyphs + aStart; - for (i = 0; i < aLength; ++i) { + CompressedGlyph *charGlyphs = mCharacterGlyphs + aRange.start; + for (i = 0; i < aRange.Length(); ++i) { uint8_t canBreak = aBreakBefore[i]; if (canBreak && !charGlyphs[i].IsClusterStart()) { // This can happen ... there is no guarantee that our linebreaking rules @@ -231,39 +230,39 @@ gfxTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, } gfxTextRun::LigatureData -gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, - PropertyProvider *aProvider) +gfxTextRun::ComputeLigatureData(Range aPartRange, PropertyProvider *aProvider) { - NS_ASSERTION(aPartStart < aPartEnd, "Computing ligature data for empty range"); - NS_ASSERTION(aPartEnd <= GetLength(), "Character length overflow"); + NS_ASSERTION(aPartRange.start < aPartRange.end, + "Computing ligature data for empty range"); + NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow"); LigatureData result; CompressedGlyph *charGlyphs = mCharacterGlyphs; uint32_t i; - for (i = aPartStart; !charGlyphs[i].IsLigatureGroupStart(); --i) { + for (i = aPartRange.start; !charGlyphs[i].IsLigatureGroupStart(); --i) { NS_ASSERTION(i > 0, "Ligature at the start of the run??"); } - result.mLigatureStart = i; - for (i = aPartStart + 1; i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) { + result.mRange.start = i; + for (i = aPartRange.start + 1; + i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) { } - result.mLigatureEnd = i; + result.mRange.end = i; - int32_t ligatureWidth = - GetAdvanceForGlyphs(result.mLigatureStart, result.mLigatureEnd); + int32_t ligatureWidth = GetAdvanceForGlyphs(result.mRange); // Count the number of started clusters we have seen uint32_t totalClusterCount = 0; uint32_t partClusterIndex = 0; uint32_t partClusterCount = 0; - for (i = result.mLigatureStart; i < result.mLigatureEnd; ++i) { + for (i = result.mRange.start; i < result.mRange.end; ++i) { // Treat the first character of the ligature as the start of a // cluster for our purposes of allocating ligature width to its // characters. - if (i == result.mLigatureStart || charGlyphs[i].IsClusterStart()) { + if (i == result.mRange.start || charGlyphs[i].IsClusterStart()) { ++totalClusterCount; - if (i < aPartStart) { + if (i < aPartRange.start) { ++partClusterIndex; - } else if (i < aPartEnd) { + } else if (i < aPartRange.end) { ++partClusterCount; } } @@ -275,7 +274,7 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, // Any rounding errors are apportioned to the final part of the ligature, // so that measuring all parts of a ligature and summing them is equal to // the ligature width. - if (aPartEnd == result.mLigatureEnd) { + if (aPartRange.end == result.mRange.end) { gfxFloat allParts = totalClusterCount * (ligatureWidth / totalClusterCount); result.mPartWidth += ligatureWidth - allParts; } @@ -296,12 +295,14 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) { gfxFont::Spacing spacing; - if (aPartStart == result.mLigatureStart) { - aProvider->GetSpacing(aPartStart, 1, &spacing); + if (aPartRange.start == result.mRange.start) { + aProvider->GetSpacing( + Range(aPartRange.start, aPartRange.start + 1), &spacing); result.mPartWidth += spacing.mBefore; } - if (aPartEnd == result.mLigatureEnd) { - aProvider->GetSpacing(aPartEnd - 1, 1, &spacing); + if (aPartRange.end == result.mRange.end) { + aProvider->GetSpacing( + Range(aPartRange.end - 1, aPartRange.end), &spacing); result.mPartWidth += spacing.mAfter; } } @@ -310,34 +311,34 @@ gfxTextRun::ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, } gfxFloat -gfxTextRun::ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd, +gfxTextRun::ComputePartialLigatureWidth(Range aPartRange, PropertyProvider *aProvider) { - if (aPartStart >= aPartEnd) + if (aPartRange.start >= aPartRange.end) return 0; - LigatureData data = ComputeLigatureData(aPartStart, aPartEnd, aProvider); + LigatureData data = ComputeLigatureData(aPartRange, aProvider); return data.mPartWidth; } int32_t -gfxTextRun::GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd) +gfxTextRun::GetAdvanceForGlyphs(Range aRange) { int32_t advance = 0; - for (auto i = aStart; i < aEnd; ++i) { + for (auto i = aRange.start; i < aRange.end; ++i) { advance += GetAdvanceForGlyph(i); } return advance; } static void -GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, +GetAdjustedSpacing(gfxTextRun *aTextRun, gfxTextRun::Range aRange, gfxTextRun::PropertyProvider *aProvider, gfxTextRun::PropertyProvider::Spacing *aSpacing) { - if (aStart >= aEnd) + if (aRange.start >= aRange.end) return; - aProvider->GetSpacing(aStart, aEnd - aStart, aSpacing); + aProvider->GetSpacing(aRange, aSpacing); #ifdef DEBUG // Check to see if we have spacing inside ligatures @@ -345,11 +346,13 @@ GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, const gfxTextRun::CompressedGlyph *charGlyphs = aTextRun->GetCharacterGlyphs(); uint32_t i; - for (i = aStart; i < aEnd; ++i) { + for (i = aRange.start; i < aRange.end; ++i) { if (!charGlyphs[i].IsLigatureGroupStart()) { - NS_ASSERTION(i == aStart || aSpacing[i - aStart].mBefore == 0, + NS_ASSERTION(i == aRange.start || + aSpacing[i - aRange.start].mBefore == 0, "Before-spacing inside a ligature!"); - NS_ASSERTION(i - 1 <= aStart || aSpacing[i - 1 - aStart].mAfter == 0, + NS_ASSERTION(i - 1 <= aRange.start || + aSpacing[i - 1 - aRange.start].mAfter == 0, "After-spacing inside a ligature!"); } } @@ -357,51 +360,53 @@ GetAdjustedSpacing(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd, } bool -gfxTextRun::GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd, - PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, +gfxTextRun::GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider, + Range aSpacingRange, nsTArray *aSpacing) { if (!aProvider || !(mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) return false; - if (!aSpacing->AppendElements(aEnd - aStart)) + if (!aSpacing->AppendElements(aRange.Length())) return false; - memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing)*(aSpacingStart - aStart)); - GetAdjustedSpacing(this, aSpacingStart, aSpacingEnd, aProvider, - aSpacing->Elements() + aSpacingStart - aStart); - memset(aSpacing->Elements() + aSpacingEnd - aStart, 0, sizeof(gfxFont::Spacing)*(aEnd - aSpacingEnd)); + auto spacingOffset = aSpacingRange.start - aRange.start; + memset(aSpacing->Elements(), 0, sizeof(gfxFont::Spacing) * spacingOffset); + GetAdjustedSpacing(this, aSpacingRange, aProvider, + aSpacing->Elements() + spacingOffset); + memset(aSpacing->Elements() + aSpacingRange.end - aRange.start, 0, + sizeof(gfxFont::Spacing) * (aRange.end - aSpacingRange.end)); return true; } void -gfxTextRun::ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd) +gfxTextRun::ShrinkToLigatureBoundaries(Range* aRange) { - if (*aStart >= *aEnd) + if (aRange->start >= aRange->end) return; CompressedGlyph *charGlyphs = mCharacterGlyphs; - while (*aStart < *aEnd && !charGlyphs[*aStart].IsLigatureGroupStart()) { - ++(*aStart); + while (aRange->start < aRange->end && + !charGlyphs[aRange->start].IsLigatureGroupStart()) { + ++aRange->start; } - if (*aEnd < GetLength()) { - while (*aEnd > *aStart && !charGlyphs[*aEnd].IsLigatureGroupStart()) { - --(*aEnd); + if (aRange->end < GetLength()) { + while (aRange->end > aRange->start && + !charGlyphs[aRange->end].IsLigatureGroupStart()) { + --aRange->end; } } } void -gfxTextRun::DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, - gfxPoint *aPt, PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, +gfxTextRun::DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt, + PropertyProvider *aProvider, Range aSpacingRange, TextRunDrawParams& aParams, uint16_t aOrientation) { AutoTArray spacingBuffer; - bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider, - aSpacingStart, aSpacingEnd, &spacingBuffer); + bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider, + aSpacingRange, &spacingBuffer); aParams.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr; - aFont->Draw(this, aStart, aEnd, aPt, aParams, aOrientation); + aFont->Draw(this, aRange.start, aRange.end, aPt, aParams, aOrientation); } static void @@ -429,16 +434,16 @@ ClipPartialLigature(const gfxTextRun* aTextRun, } void -gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, +gfxTextRun::DrawPartialLigature(gfxFont *aFont, Range aRange, gfxPoint *aPt, PropertyProvider *aProvider, TextRunDrawParams& aParams, uint16_t aOrientation) { - if (aStart >= aEnd) { + if (aRange.start >= aRange.end) { return; } // Draw partial ligature. We hack this by clipping the ligature. - LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider); + LigatureData data = ComputeLigatureData(aRange, aProvider); gfxRect clipExtents = aParams.context->GetClipExtents(); gfxFloat start, end; if (aParams.isVerticalRun) { @@ -473,8 +478,8 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, pt = gfxPoint(aPt->x - aParams.direction * data.mPartAdvance, aPt->y); } - DrawGlyphs(aFont, data.mLigatureStart, data.mLigatureEnd, &pt, - aProvider, aStart, aEnd, aParams, aOrientation); + DrawGlyphs(aFont, data.mRange, &pt, + aProvider, aRange, aParams, aOrientation); aParams.context->Restore(); if (aParams.isVerticalRun) { @@ -484,18 +489,31 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, } } -// returns true if a glyph run is using a font with synthetic bolding enabled, false otherwise +// Returns true if a glyph run is using a font with synthetic bolding enabled, +// or a color font (COLR/SVG/sbix/CBDT), false otherwise. This is used to +// check whether the text run needs to be explicitly composited in order to +// support opacity. static bool -HasSyntheticBold(gfxTextRun *aRun, uint32_t aStart, uint32_t aLength) +HasSyntheticBoldOrColor(gfxTextRun *aRun, gfxTextRun::Range aRange) { - gfxTextRun::GlyphRunIterator iter(aRun, aStart, aLength); + gfxTextRun::GlyphRunIterator iter(aRun, aRange); while (iter.NextRun()) { gfxFont *font = iter.GetGlyphRun()->mFont; - if (font && font->IsSyntheticBold()) { - return true; + if (font) { + if (font->IsSyntheticBold()) { + return true; + } + gfxFontEntry* fe = font->GetFontEntry(); + if (fe->TryGetSVGData(font) || fe->TryGetColorGlyphs()) { + return true; + } +#if defined(XP_MACOSX) // sbix fonts only supported via Core Text + if (fe->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'))) { + return true; + } +#endif } } - return false; } @@ -546,23 +564,20 @@ struct BufferAlphaColor { }; void -gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, - uint32_t aStart, uint32_t aLength, - PropertyProvider *aProvider, gfxFloat *aAdvanceWidth, - gfxTextContextPaint *aContextPaint, - gfxTextRunDrawCallbacks *aCallbacks) +gfxTextRun::Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams) { - NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range"); - NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH || - !(int(aDrawMode) & int(DrawMode::GLYPH_PATH)), + NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range"); + NS_ASSERTION(aParams.drawMode == DrawMode::GLYPH_PATH || + !(int(aParams.drawMode) & int(DrawMode::GLYPH_PATH)), "GLYPH_PATH cannot be used with GLYPH_FILL, GLYPH_STROKE or GLYPH_STROKE_UNDERNEATH"); - NS_ASSERTION(aDrawMode == DrawMode::GLYPH_PATH || !aCallbacks, + NS_ASSERTION(aParams.drawMode == DrawMode::GLYPH_PATH || !aParams.callbacks, "callback must not be specified unless using GLYPH_PATH"); bool skipDrawing = mSkipDrawing; - if (aDrawMode == DrawMode::GLYPH_FILL) { + if (aParams.drawMode == DrawMode::GLYPH_FILL) { Color currentColor; - if (aContext->GetDeviceColor(currentColor) && currentColor.a == 0) { + if (aParams.context->GetDeviceColor(currentColor) && + currentColor.a == 0) { skipDrawing = true; } } @@ -572,12 +587,11 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, if (skipDrawing) { // We don't need to draw anything; // but if the caller wants advance width, we need to compute it here - if (aAdvanceWidth) { - gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, - gfxFont::LOOSE_INK_EXTENTS, - aContext->GetDrawTarget(), - aProvider); - *aAdvanceWidth = metrics.mAdvanceWidth * direction; + if (aParams.advanceWidth) { + gfxTextRun::Metrics metrics = MeasureText( + aRange, gfxFont::LOOSE_INK_EXTENTS, + aParams.context->GetDrawTarget(), aParams.provider); + *aParams.advanceWidth = metrics.mAdvanceWidth * direction; } // return without drawing @@ -586,19 +600,18 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, // synthetic bolding draws glyphs twice ==> colors with opacity won't draw // correctly unless first drawn without alpha - BufferAlphaColor syntheticBoldBuffer(aContext); + BufferAlphaColor syntheticBoldBuffer(aParams.context); Color currentColor; bool needToRestore = false; - if (aDrawMode == DrawMode::GLYPH_FILL && - HasNonOpaqueNonTransparentColor(aContext, currentColor) && - HasSyntheticBold(this, aStart, aLength)) { + if (aParams.drawMode == DrawMode::GLYPH_FILL && + HasNonOpaqueNonTransparentColor(aParams.context, currentColor) && + HasSyntheticBoldOrColor(this, aRange)) { needToRestore = true; // measure text, use the bounding box - gfxTextRun::Metrics metrics = MeasureText(aStart, aLength, - gfxFont::LOOSE_INK_EXTENTS, - aContext->GetDrawTarget(), - aProvider); + gfxTextRun::Metrics metrics = MeasureText( + aRange, gfxFont::LOOSE_INK_EXTENTS, + aParams.context->GetDrawTarget(), aParams.provider); metrics.mBoundingBox.MoveBy(aPt); syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor, GetAppUnitsPerDevUnit()); @@ -607,46 +620,48 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, // Set up parameters that will be constant across all glyph runs we need // to draw, regardless of the font used. TextRunDrawParams params; - params.context = aContext; + params.context = aParams.context; params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit()); params.isVerticalRun = IsVertical(); params.isRTL = IsRightToLeft(); params.direction = direction; - params.drawMode = aDrawMode; - params.callbacks = aCallbacks; - params.runContextPaint = aContextPaint; - params.paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs; - params.dt = aContext->GetDrawTarget(); - params.fontSmoothingBGColor = aContext->GetFontSmoothingBackgroundColor(); + params.drawMode = aParams.drawMode; + params.callbacks = aParams.callbacks; + params.runContextPaint = aParams.contextPaint; + params.paintSVGGlyphs = !aParams.callbacks || + aParams.callbacks->mShouldPaintSVGGlyphs; + params.dt = aParams.context->GetDrawTarget(); + params.fontSmoothingBGColor = + aParams.context->GetFontSmoothingBackgroundColor(); - GlyphRunIterator iter(this, aStart, aLength); + GlyphRunIterator iter(this, aRange); gfxFloat advance = 0.0; while (iter.NextRun()) { gfxFont *font = iter.GetGlyphRun()->mFont; uint32_t start = iter.GetStringStart(); uint32_t end = iter.GetStringEnd(); - uint32_t ligatureRunStart = start; - uint32_t ligatureRunEnd = end; - ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); + Range ligatureRange(start, end); + ShrinkToLigatureBoundaries(&ligatureRange); - bool drawPartial = aDrawMode == DrawMode::GLYPH_FILL || - (aDrawMode == DrawMode::GLYPH_PATH && aCallbacks); + bool drawPartial = aParams.drawMode == DrawMode::GLYPH_FILL || + (aParams.drawMode == DrawMode::GLYPH_PATH && + aParams.callbacks); gfxPoint origPt = aPt; if (drawPartial) { - DrawPartialLigature(font, start, ligatureRunStart, &aPt, - aProvider, params, + DrawPartialLigature(font, Range(start, ligatureRange.start), + &aPt, aParams.provider, params, iter.GetGlyphRun()->mOrientation); } - DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &aPt, - aProvider, ligatureRunStart, ligatureRunEnd, params, + DrawGlyphs(font, ligatureRange, &aPt, + aParams.provider, ligatureRange, params, iter.GetGlyphRun()->mOrientation); if (drawPartial) { - DrawPartialLigature(font, ligatureRunEnd, end, &aPt, - aProvider, params, + DrawPartialLigature(font, Range(ligatureRange.end, end), + &aPt, aParams.provider, params, iter.GetGlyphRun()->mOrientation); } @@ -662,8 +677,8 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, syntheticBoldBuffer.PopAlpha(); } - if (aAdvanceWidth) { - *aAdvanceWidth = advance; + if (aParams.advanceWidth) { + *aParams.advanceWidth = advance; } } @@ -671,10 +686,9 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode, void gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark, gfxFloat aMarkAdvance, gfxPoint aPt, - uint32_t aStart, uint32_t aLength, - PropertyProvider* aProvider) + Range aRange, PropertyProvider* aProvider) { - MOZ_ASSERT(aStart + aLength <= GetLength()); + MOZ_ASSERT(aRange.end <= GetLength()); EmphasisMarkDrawParams params; params.context = aContext; @@ -686,69 +700,65 @@ gfxTextRun::DrawEmphasisMarks(gfxContext *aContext, gfxTextRun* aMark, gfxFloat& inlineCoord = params.isVertical ? aPt.y : aPt.x; gfxFloat direction = params.direction; - GlyphRunIterator iter(this, aStart, aLength); + GlyphRunIterator iter(this, aRange); while (iter.NextRun()) { gfxFont* font = iter.GetGlyphRun()->mFont; uint32_t start = iter.GetStringStart(); uint32_t end = iter.GetStringEnd(); - uint32_t ligatureRunStart = start; - uint32_t ligatureRunEnd = end; - ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); + Range ligatureRange(start, end); + ShrinkToLigatureBoundaries(&ligatureRange); - inlineCoord += direction * - ComputePartialLigatureWidth(start, ligatureRunStart, aProvider); + inlineCoord += direction * ComputePartialLigatureWidth( + Range(start, ligatureRange.start), aProvider); AutoTArray spacingBuffer; bool haveSpacing = GetAdjustedSpacingArray( - ligatureRunStart, ligatureRunEnd, aProvider, - ligatureRunStart, ligatureRunEnd, &spacingBuffer); + ligatureRange, aProvider, ligatureRange, &spacingBuffer); params.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr; - font->DrawEmphasisMarks(this, &aPt, ligatureRunStart, - ligatureRunEnd - ligatureRunStart, params); + font->DrawEmphasisMarks(this, &aPt, ligatureRange.start, + ligatureRange.Length(), params); - inlineCoord += direction * - ComputePartialLigatureWidth(ligatureRunEnd, end, aProvider); + inlineCoord += direction * ComputePartialLigatureWidth( + Range(ligatureRange.end, end), aProvider); } } void -gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, - uint32_t aStart, uint32_t aEnd, +gfxTextRun::AccumulateMetricsForRun(gfxFont *aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, + Range aSpacingRange, uint16_t aOrientation, Metrics *aMetrics) { AutoTArray spacingBuffer; - bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider, - aSpacingStart, aSpacingEnd, &spacingBuffer); - Metrics metrics = aFont->Measure(this, aStart, aEnd, aBoundingBoxType, - aRefDrawTarget, + bool haveSpacing = GetAdjustedSpacingArray(aRange, aProvider, + aSpacingRange, &spacingBuffer); + Metrics metrics = aFont->Measure(this, aRange.start, aRange.end, + aBoundingBoxType, aRefDrawTarget, haveSpacing ? spacingBuffer.Elements() : nullptr, aOrientation); aMetrics->CombineWith(metrics, IsRightToLeft()); } void -gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, - uint32_t aStart, uint32_t aEnd, +gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, PropertyProvider *aProvider, uint16_t aOrientation, Metrics *aMetrics) { - if (aStart >= aEnd) + if (aRange.start >= aRange.end) return; // Measure partial ligature. We hack this by clipping the metrics in the // same way we clip the drawing. - LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider); + LigatureData data = ComputeLigatureData(aRange, aProvider); // First measure the complete ligature Metrics metrics; - AccumulateMetricsForRun(aFont, data.mLigatureStart, data.mLigatureEnd, + AccumulateMetricsForRun(aFont, data.mRange, aBoundingBoxType, aRefDrawTarget, - aProvider, aStart, aEnd, aOrientation, &metrics); + aProvider, aRange, aOrientation, &metrics); // Clip the bounding box to the ligature part gfxFloat bboxLeft = metrics.mBoundingBox.X(); @@ -770,24 +780,24 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, } gfxTextRun::Metrics -gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, +gfxTextRun::MeasureText(Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, PropertyProvider *aProvider) { - NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range"); + NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range"); Metrics accumulatedMetrics; - GlyphRunIterator iter(this, aStart, aLength); + GlyphRunIterator iter(this, aRange); while (iter.NextRun()) { gfxFont *font = iter.GetGlyphRun()->mFont; uint32_t start = iter.GetStringStart(); uint32_t end = iter.GetStringEnd(); - uint32_t ligatureRunStart = start; - uint32_t ligatureRunEnd = end; - ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); + Range ligatureRange(start, end); + ShrinkToLigatureBoundaries(&ligatureRange); - AccumulatePartialLigatureMetrics(font, start, ligatureRunStart, + AccumulatePartialLigatureMetrics( + font, Range(start, ligatureRange.start), aBoundingBoxType, aRefDrawTarget, aProvider, iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); @@ -797,11 +807,12 @@ gfxTextRun::MeasureText(uint32_t aStart, uint32_t aLength, // by getting some ascent/descent from the font and using our stored // advance widths. AccumulateMetricsForRun(font, - ligatureRunStart, ligatureRunEnd, aBoundingBoxType, - aRefDrawTarget, aProvider, ligatureRunStart, ligatureRunEnd, + ligatureRange, aBoundingBoxType, + aRefDrawTarget, aProvider, ligatureRange, iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); - AccumulatePartialLigatureMetrics(font, ligatureRunEnd, end, + AccumulatePartialLigatureMetrics( + font, Range(ligatureRange.end, end), aBoundingBoxType, aRefDrawTarget, aProvider, iter.GetGlyphRun()->mOrientation, &accumulatedMetrics); } @@ -829,13 +840,12 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, NS_ASSERTION(aStart + aMaxLength <= GetLength(), "Substring out of range"); - uint32_t bufferStart = aStart; - uint32_t bufferLength = std::min(aMaxLength, MEASUREMENT_BUFFER_SIZE); + Range bufferRange(aStart, aStart + + std::min(aMaxLength, MEASUREMENT_BUFFER_SIZE)); PropertyProvider::Spacing spacingBuffer[MEASUREMENT_BUFFER_SIZE]; bool haveSpacing = aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING) != 0; if (haveSpacing) { - GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider, - spacingBuffer); + GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer); } bool hyphenBuffer[MEASUREMENT_BUFFER_SIZE]; bool haveHyphenation = aProvider && @@ -843,8 +853,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, (aProvider->GetHyphensOption() == NS_STYLE_HYPHENS_MANUAL && (mFlags & gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS) != 0)); if (haveHyphenation) { - aProvider->GetHyphenationBreaks(bufferStart, bufferLength, - hyphenBuffer); + aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer); } gfxFloat width = 0; @@ -860,23 +869,21 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, uint32_t end = aStart + aMaxLength; bool lastBreakUsedHyphenation = false; - uint32_t ligatureRunStart = aStart; - uint32_t ligatureRunEnd = end; - ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); + Range ligatureRange(aStart, end); + ShrinkToLigatureBoundaries(&ligatureRange); uint32_t i; for (i = aStart; i < end; ++i) { - if (i >= bufferStart + bufferLength) { + if (i >= bufferRange.end) { // Fetch more spacing and hyphenation data - bufferStart = i; - bufferLength = std::min(aStart + aMaxLength, i + MEASUREMENT_BUFFER_SIZE) - i; + bufferRange.start = i; + bufferRange.end = std::min(aStart + aMaxLength, + i + MEASUREMENT_BUFFER_SIZE); if (haveSpacing) { - GetAdjustedSpacing(this, bufferStart, bufferStart + bufferLength, aProvider, - spacingBuffer); + GetAdjustedSpacing(this, bufferRange, aProvider, spacingBuffer); } if (haveHyphenation) { - aProvider->GetHyphenationBreaks(bufferStart, bufferLength, - hyphenBuffer); + aProvider->GetHyphenationBreaks(bufferRange, hyphenBuffer); } } @@ -887,8 +894,8 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, if (aSuppressBreak != eSuppressAllBreaks && (aSuppressBreak != eSuppressInitialBreak || i > aStart)) { bool atNaturalBreak = mCharacterGlyphs[i].CanBreakBefore() == 1; - bool atHyphenationBreak = - !atNaturalBreak && haveHyphenation && hyphenBuffer[i - bufferStart]; + bool atHyphenationBreak = !atNaturalBreak && + haveHyphenation && hyphenBuffer[i - bufferRange.start]; bool atBreak = atNaturalBreak || atHyphenationBreak; bool wordWrapping = aCanWordWrap && mCharacterGlyphs[i].IsClusterStart() && @@ -921,14 +928,16 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, } gfxFloat charAdvance; - if (i >= ligatureRunStart && i < ligatureRunEnd) { - charAdvance = GetAdvanceForGlyphs(i, i + 1); + if (i >= ligatureRange.start && i < ligatureRange.end) { + charAdvance = GetAdvanceForGlyphs(Range(i, i + 1)); if (haveSpacing) { - PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart]; + PropertyProvider::Spacing *space = + &spacingBuffer[i - bufferRange.start]; charAdvance += space->mBefore + space->mAfter; } } else { - charAdvance = ComputePartialLigatureWidth(i, i + 1, aProvider); + charAdvance = + ComputePartialLigatureWidth(Range(i, i + 1), aProvider); } advance += charAdvance; @@ -965,13 +974,13 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, } if (aMetrics) { - *aMetrics = MeasureText(aStart, charsFit, aBoundingBoxType, + auto fitEnd = aStart + charsFit; + *aMetrics = MeasureText(Range(aStart, fitEnd), aBoundingBoxType, aRefDrawTarget, aProvider); if (trimmableChars) { Metrics trimMetrics = - MeasureText(aStart + charsFit - trimmableChars, - trimmableChars, aBoundingBoxType, - aRefDrawTarget, aProvider); + MeasureText(Range(fitEnd - trimmableChars, fitEnd), + aBoundingBoxType, aRefDrawTarget, aProvider); aMetrics->mAdvanceWidth -= trimMetrics.mAdvanceWidth; } } @@ -993,18 +1002,19 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength, } gfxFloat -gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength, - PropertyProvider *aProvider, +gfxTextRun::GetAdvanceWidth(Range aRange, PropertyProvider *aProvider, PropertyProvider::Spacing* aSpacing) { - NS_ASSERTION(aStart + aLength <= GetLength(), "Substring out of range"); + NS_ASSERTION(aRange.end <= GetLength(), "Substring out of range"); - uint32_t ligatureRunStart = aStart; - uint32_t ligatureRunEnd = aStart + aLength; - ShrinkToLigatureBoundaries(&ligatureRunStart, &ligatureRunEnd); + Range ligatureRange = aRange; + ShrinkToLigatureBoundaries(&ligatureRange); - gfxFloat result = ComputePartialLigatureWidth(aStart, ligatureRunStart, aProvider) + - ComputePartialLigatureWidth(ligatureRunEnd, aStart + aLength, aProvider); + gfxFloat result = + ComputePartialLigatureWidth(Range(aRange.start, ligatureRange.start), + aProvider) + + ComputePartialLigatureWidth(Range(ligatureRange.end, aRange.end), + aProvider); if (aSpacing) { aSpacing->mBefore = aSpacing->mAfter = 0; @@ -1015,10 +1025,10 @@ gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength, if (aProvider && (mFlags & gfxTextRunFactory::TEXT_ENABLE_SPACING)) { uint32_t i; AutoTArray spacingBuffer; - if (spacingBuffer.AppendElements(aLength)) { - GetAdjustedSpacing(this, ligatureRunStart, ligatureRunEnd, aProvider, + if (spacingBuffer.AppendElements(aRange.Length())) { + GetAdjustedSpacing(this, ligatureRange, aProvider, spacingBuffer.Elements()); - for (i = 0; i < ligatureRunEnd - ligatureRunStart; ++i) { + for (i = 0; i < ligatureRange.Length(); ++i) { PropertyProvider::Spacing *space = &spacingBuffer[i]; result += space->mBefore + space->mAfter; } @@ -1029,11 +1039,11 @@ gfxTextRun::GetAdvanceWidth(uint32_t aStart, uint32_t aLength, } } - return result + GetAdvanceForGlyphs(ligatureRunStart, ligatureRunEnd); + return result + GetAdvanceForGlyphs(ligatureRange); } bool -gfxTextRun::SetLineBreaks(uint32_t aStart, uint32_t aLength, +gfxTextRun::SetLineBreaks(Range aRange, bool aLineBreakBefore, bool aLineBreakAfter, gfxFloat *aAdvanceWidthDelta) { @@ -1231,12 +1241,11 @@ gfxTextRun::CopyGlyphDataFrom(gfxShapedWord *aShapedWord, uint32_t aOffset) } void -gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, - uint32_t aLength, uint32_t aDest) +gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest) { - NS_ASSERTION(aStart + aLength <= aSource->GetLength(), + NS_ASSERTION(aRange.end <= aSource->GetLength(), "Source substring out of range"); - NS_ASSERTION(aDest + aLength <= GetLength(), + NS_ASSERTION(aDest + aRange.Length() <= GetLength(), "Destination substring out of range"); if (aSource->mSkipDrawing) { @@ -1244,9 +1253,9 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, } // Copy base glyph data, and DetailedGlyph data where present - const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aStart; + const CompressedGlyph *srcGlyphs = aSource->mCharacterGlyphs + aRange.start; CompressedGlyph *dstGlyphs = mCharacterGlyphs + aDest; - for (uint32_t i = 0; i < aLength; ++i) { + for (uint32_t i = 0; i < aRange.Length(); ++i) { CompressedGlyph g = srcGlyphs[i]; g.SetCanBreakBefore(!g.IsClusterStart() ? CompressedGlyph::FLAG_BREAK_TYPE_NONE : @@ -1256,7 +1265,8 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, if (count > 0) { DetailedGlyph *dst = AllocateDetailedGlyphs(i + aDest, count); if (dst) { - DetailedGlyph *src = aSource->GetDetailedGlyphs(i + aStart); + DetailedGlyph *src = + aSource->GetDetailedGlyphs(i + aRange.start); if (src) { ::memcpy(dst, src, count * sizeof(DetailedGlyph)); } else { @@ -1271,7 +1281,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, } // Copy glyph runs - GlyphRunIterator iter(aSource, aStart, aLength); + GlyphRunIterator iter(aSource, aRange); #ifdef DEBUG GlyphRun *prevRun = nullptr; #endif @@ -1302,7 +1312,7 @@ gfxTextRun::CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, "Ended font run in the middle of a cluster"); nsresult rv = AddGlyphRun(font, iter.GetGlyphRun()->mMatchType, - start - aStart + aDest, false, + start - aRange.start + aDest, false, iter.GetGlyphRun()->mOrientation); if (NS_FAILED(rv)) return; @@ -1482,11 +1492,11 @@ gfxTextRun::ClusterIterator::NextCluster() return false; } -uint32_t -gfxTextRun::ClusterIterator::ClusterLength() const +gfxTextRun::Range +gfxTextRun::ClusterIterator::ClusterRange() const { if (mCurrentChar == uint32_t(-1)) { - return 0; + return Range(0, 0); } uint32_t i = mCurrentChar, @@ -1497,7 +1507,7 @@ gfxTextRun::ClusterIterator::ClusterLength() const } } - return i - mCurrentChar; + return Range(mCurrentChar, i); } gfxFloat @@ -1507,7 +1517,7 @@ gfxTextRun::ClusterIterator::ClusterAdvance(PropertyProvider *aProvider) const return 0; } - return mTextRun->GetAdvanceWidth(mCurrentChar, ClusterLength(), aProvider); + return mTextRun->GetAdvanceWidth(ClusterRange(), aProvider); } size_t @@ -1647,8 +1657,8 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, } // Not known in the user font set ==> check system fonts + gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList(); if (!family) { - gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList(); family = fontList->FindFamily(aName, &mStyle, mDevToCssSize); } @@ -2056,8 +2066,7 @@ gfxFontGroup::GetHyphenWidth(gfxTextRun::PropertyProvider *aProvider) nsAutoPtr hyphRun(MakeHyphenTextRun(dt, aProvider->GetAppUnitsPerDevUnit())); - mHyphenWidth = hyphRun.get() ? - hyphRun->GetAdvanceWidth(0, hyphRun->GetLength(), nullptr) : 0; + mHyphenWidth = hyphRun.get() ? hyphRun->GetAdvanceWidth() : 0; } } return mHyphenWidth; diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index e1091085c5..60e2d3a39f 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -134,10 +134,23 @@ public: return mCharacterGlyphs[aPos].CharMayHaveEmphasisMark(); } - // All uint32_t aStart, uint32_t aLength ranges below are restricted to - // grapheme cluster boundaries! All offsets are in terms of the string - // passed into MakeTextRun. - + // All offsets are in terms of the string passed into MakeTextRun. + + // Describe range [start, end) of a text run. The range is + // restricted to grapheme cluster boundaries. + struct Range + { + uint32_t start; + uint32_t end; + uint32_t Length() const { return end - start; } + + Range() : start(0), end(0) {} + Range(uint32_t aStart, uint32_t aEnd) + : start(aStart), end(aEnd) {} + explicit Range(gfxTextRun* aTextRun) + : start(0), end(aTextRun->GetLength()) {} + }; + // All coordinates are in layout/app units /** @@ -152,8 +165,7 @@ public: * @return true if this changed the linebreaks, false if the new line * breaks are the same as the old */ - virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, - uint8_t *aBreakBefore); + virtual bool SetPotentialLineBreaks(Range aRange, uint8_t *aBreakBefore); /** * Layout provides PropertyProvider objects. These allow detection of @@ -169,8 +181,7 @@ public: public: // Detect hyphenation break opportunities in the given range; breaks // not at cluster boundaries will be ignored. - virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, - bool *aBreakBefore) = 0; + virtual void GetHyphenationBreaks(Range aRange, bool *aBreakBefore) = 0; // Returns the provider's hyphenation setting, so callers can decide // whether it is necessary to call GetHyphenationBreaks. @@ -189,8 +200,7 @@ public: * CLUSTER_START, then character i-1 must have zero after-spacing and * character i must have zero before-spacing. */ - virtual void GetSpacing(uint32_t aStart, uint32_t aLength, - Spacing *aSpacing) = 0; + virtual void GetSpacing(Range aRange, Spacing *aSpacing) = 0; // Returns a gfxContext that can be used to measure the hyphen glyph. // Only called if the hyphen width is requested. @@ -213,7 +223,7 @@ public: return mCurrentChar; } - uint32_t ClusterLength() const; + Range ClusterRange() const; gfxFloat ClusterAdvance(PropertyProvider *aProvider) const; @@ -222,33 +232,39 @@ public: uint32_t mCurrentChar; }; + struct DrawParams + { + gfxContext* context; + DrawMode drawMode = DrawMode::GLYPH_FILL; + PropertyProvider* provider = nullptr; + // If non-null, the advance width of the substring is set. + gfxFloat* advanceWidth = nullptr; + gfxTextContextPaint* contextPaint = nullptr; + gfxTextRunDrawCallbacks* callbacks = nullptr; + explicit DrawParams(gfxContext* aContext) : context(aContext) {} + }; + /** * Draws a substring. Uses only GetSpacing from aBreakProvider. * The provided point is the baseline origin on the left of the string * for LTR, on the right of the string for RTL. - * @param aAdvanceWidth if non-null, the advance width of the substring - * is returned here. * * Drawing should respect advance widths in the sense that for LTR runs, - * Draw(ctx, pt, offset1, length1, dirty, &provider, &advance) followed by - * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1 + length1, length2, - * dirty, &provider, nullptr) should have the same effect as - * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). + * Draw(Range(start, middle), pt, ...) followed by + * Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...) + * should have the same effect as + * Draw(Range(start, end), pt, ...) + * * For RTL runs the rule is: - * Draw(ctx, pt, offset1 + length1, length2, dirty, &provider, &advance) followed by - * Draw(ctx, gfxPoint(pt.x + advance, pt.y), offset1, length1, - * dirty, &provider, nullptr) should have the same effect as - * Draw(ctx, pt, offset1, length1+length2, dirty, &provider, nullptr). + * Draw(Range(middle, end), pt, ...) followed by + * Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...) + * should have the same effect as + * Draw(Range(start, end), pt, ...) * * Glyphs should be drawn in logical content order, which can be significant * if they overlap (perhaps due to negative spacing). */ - void Draw(gfxContext *aContext, gfxPoint aPt, - DrawMode aDrawMode, - uint32_t aStart, uint32_t aLength, - PropertyProvider *aProvider, - gfxFloat *aAdvanceWidth, gfxTextContextPaint *aContextPaint, - gfxTextRunDrawCallbacks *aCallbacks = nullptr); + void Draw(Range aRange, gfxPoint aPt, const DrawParams& aParams); /** * Draws the emphasis marks for this text run. Uses only GetSpacing @@ -257,19 +273,25 @@ public: */ void DrawEmphasisMarks(gfxContext* aContext, gfxTextRun* aMark, gfxFloat aMarkAdvance, gfxPoint aPt, - uint32_t aStart, uint32_t aLength, - PropertyProvider* aProvider); + Range aRange, PropertyProvider* aProvider); /** * Computes the ReflowMetrics for a substring. * Uses GetSpacing from aBreakProvider. * @param aBoundingBoxType which kind of bounding box (loose/tight) */ - Metrics MeasureText(uint32_t aStart, uint32_t aLength, + Metrics MeasureText(Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aDrawTargetForTightBoundingBox, PropertyProvider* aProvider); + Metrics MeasureText(gfxFont::BoundingBoxType aBoundingBoxType, + DrawTarget* aDrawTargetForTightBoundingBox, + PropertyProvider* aProvider = nullptr) { + return MeasureText(Range(this), aBoundingBoxType, + aDrawTargetForTightBoundingBox, aProvider); + } + /** * Computes just the advance width for a substring. * Uses GetSpacing from aBreakProvider. @@ -277,13 +299,16 @@ public: * the substring would be returned in it. NOTE: the spacing is * included in the advance width. */ - gfxFloat GetAdvanceWidth(uint32_t aStart, uint32_t aLength, - PropertyProvider *aProvider, + gfxFloat GetAdvanceWidth(Range aRange, PropertyProvider *aProvider, PropertyProvider::Spacing* aSpacing = nullptr); + gfxFloat GetAdvanceWidth() { + return GetAdvanceWidth(Range(this), nullptr); + } + /** * Clear all stored line breaks for the given range (both before and after), - * and then set the line-break state before aStart to aBreakBefore and + * and then set the line-break state before aRange.start to aBreakBefore and * after the last cluster to aBreakAfter. * * We require that before and after line breaks be consistent. For clusters @@ -308,9 +333,9 @@ public: * @param aAdvanceWidthDelta if non-null, returns the change in advance * width of the given range. */ - virtual bool SetLineBreaks(uint32_t aStart, uint32_t aLength, - bool aLineBreakBefore, bool aLineBreakAfter, - gfxFloat* aAdvanceWidthDelta); + virtual bool SetLineBreaks(Range aRange, + bool aLineBreakBefore, bool aLineBreakAfter, + gfxFloat* aAdvanceWidthDelta); enum SuppressBreak { eNoSuppressBreak, @@ -423,9 +448,11 @@ public: class GlyphRunIterator { public: - GlyphRunIterator(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aLength) - : mTextRun(aTextRun), mStartOffset(aStart), mEndOffset(aStart + aLength) { - mNextIndex = mTextRun->FindFirstGlyphRunContaining(aStart); + GlyphRunIterator(gfxTextRun *aTextRun, Range aRange) + : mTextRun(aTextRun) + , mStartOffset(aRange.start) + , mEndOffset(aRange.end) { + mNextIndex = mTextRun->FindFirstGlyphRunContaining(aRange.start); } bool NextRun(); GlyphRun *GetGlyphRun() { return mGlyphRun; } @@ -546,8 +573,7 @@ public: // Copy glyph data for a range of characters from aSource to this // textrun. - void CopyGlyphDataFrom(gfxTextRun *aSource, uint32_t aStart, - uint32_t aLength, uint32_t aDest); + void CopyGlyphDataFrom(gfxTextRun *aSource, Range aRange, uint32_t aDest); nsExpirationState *GetExpirationState() { return &mExpirationState; } @@ -560,9 +586,8 @@ public: void ReleaseFontGroup(); struct LigatureData { - // textrun offsets of the start and end of the containing ligature - uint32_t mLigatureStart; - uint32_t mLigatureEnd; + // textrun range of the containing ligature + Range mRange; // appunits advance to the start of the ligature part within the ligature; // never includes any spacing gfxFloat mPartAdvance; @@ -658,16 +683,15 @@ private: // **** general helpers **** // Get the total advance for a range of glyphs. - int32_t GetAdvanceForGlyphs(uint32_t aStart, uint32_t aEnd); + int32_t GetAdvanceForGlyphs(Range aRange); // Spacing for characters outside the range aSpacingStart/aSpacingEnd // is assumed to be zero; such characters are not passed to aProvider. // This is useful to protect aProvider from being passed character indices // it is not currently able to handle. - bool GetAdjustedSpacingArray(uint32_t aStart, uint32_t aEnd, - PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, - nsTArray *aSpacing); + bool GetAdjustedSpacingArray(Range aRange, PropertyProvider *aProvider, + Range aSpacingRange, + nsTArray *aSpacing); CompressedGlyph& EnsureComplexGlyph(uint32_t aIndex) { @@ -680,20 +704,20 @@ private: // to handle requests that begin or end inside a ligature) // if aProvider is null then mBeforeSpacing and mAfterSpacing are set to zero - LigatureData ComputeLigatureData(uint32_t aPartStart, uint32_t aPartEnd, + LigatureData ComputeLigatureData(Range aPartRange, PropertyProvider *aProvider); - gfxFloat ComputePartialLigatureWidth(uint32_t aPartStart, uint32_t aPartEnd, + gfxFloat ComputePartialLigatureWidth(Range aPartRange, PropertyProvider *aProvider); - void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, + void DrawPartialLigature(gfxFont *aFont, Range aRange, gfxPoint *aPt, PropertyProvider *aProvider, TextRunDrawParams& aParams, uint16_t aOrientation); - // Advance aStart to the start of the nearest ligature; back up aEnd - // to the nearest ligature end; may result in *aStart == *aEnd - void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd); + // Advance aRange.start to the start of the nearest ligature, back + // up aRange.end to the nearest ligature end; may result in + // aRange->start == aRange->end. + void ShrinkToLigatureBoundaries(Range* aRange); // result in appunits - gfxFloat GetPartialLigatureWidth(uint32_t aStart, uint32_t aEnd, PropertyProvider *aProvider); - void AccumulatePartialLigatureMetrics(gfxFont *aFont, - uint32_t aStart, uint32_t aEnd, + gfxFloat GetPartialLigatureWidth(Range aRange, PropertyProvider *aProvider); + void AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, PropertyProvider *aProvider, @@ -701,18 +725,17 @@ private: Metrics *aMetrics); // **** measurement helper **** - void AccumulateMetricsForRun(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, + void AccumulateMetricsForRun(gfxFont *aFont, Range aRange, gfxFont::BoundingBoxType aBoundingBoxType, DrawTarget* aRefDrawTarget, PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, + Range aSpacingRange, uint16_t aOrientation, Metrics *aMetrics); // **** drawing helper **** - void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd, - gfxPoint *aPt, PropertyProvider *aProvider, - uint32_t aSpacingStart, uint32_t aSpacingEnd, + void DrawGlyphs(gfxFont *aFont, Range aRange, gfxPoint *aPt, + PropertyProvider *aProvider, Range aSpacingRange, TextRunDrawParams& aParams, uint16_t aOrientation); // XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*, diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index a882007c3c..1beced6b73 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -533,6 +533,15 @@ gfxWindowsPlatform::UpdateRenderMode() } } +void +gfxWindowsPlatform::ForceDeviceReset(ForcedDeviceResetReason aReason) +{ + Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON, uint32_t(aReason)); + + mDeviceResetReason = DeviceResetReason::FORCED_RESET; + mHasDeviceReset = true; +} + mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers) { diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 1b99fbe42c..51011799ef 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -145,6 +145,11 @@ public: */ void UpdateRenderMode(); + /** + * Forces all GPU resources to be recreated on the next frame. + */ + void ForceDeviceReset(ForcedDeviceResetReason aReason); + /** * Verifies a D2D device is present and working, will attempt to create one * it is non-functional or non-existant. diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index 0ebef17059..ef76f70c7a 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -148,7 +148,6 @@ InitializeOculusCAPI() } if (!ovrlib) { - printf_stderr("Failed to load Oculus VR library!\n"); return false; } } diff --git a/gfx/vr/gfxVROculus050.cpp b/gfx/vr/gfxVROculus050.cpp index fe93cee841..dd526d3a48 100644 --- a/gfx/vr/gfxVROculus050.cpp +++ b/gfx/vr/gfxVROculus050.cpp @@ -153,7 +153,6 @@ InitializeOculusCAPI() } if (!ovrlib) { - printf_stderr("Failed to load Oculus VR library!\n"); return false; } } diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp index 56a2b865ec..0080323cf0 100644 --- a/gfx/vr/ipc/VRManagerParent.cpp +++ b/gfx/vr/ipc/VRManagerParent.cpp @@ -106,7 +106,6 @@ VRManagerParent::CreateSameProcess() void VRManagerParent::DeferredDestroy() { - MOZ_ASSERT(mCompositorThreadHolder); mCompositorThreadHolder = nullptr; mSelfRef = nullptr; } diff --git a/hal/gonk/GonkFMRadio.cpp b/hal/gonk/GonkFMRadio.cpp index 383e98f428..a88d544f60 100644 --- a/hal/gonk/GonkFMRadio.cpp +++ b/hal/gonk/GonkFMRadio.cpp @@ -78,7 +78,7 @@ static bool sRDSSupported; static int setControl(uint32_t id, int32_t value) { - struct v4l2_control control; + struct v4l2_control control = {0}; control.id = id; control.value = value; return ioctl(sRadioFD, VIDIOC_S_CTRL, &control); @@ -309,7 +309,7 @@ EnableFMRadio(const hal::FMRadioSettings& aInfo) return; } - struct v4l2_capability cap; + struct v4l2_capability cap = {{0}}; int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap); if (rc < 0) { HAL_LOG("Unable to query radio device"); @@ -487,7 +487,7 @@ GetFMRadioFrequency() if (!sRadioEnabled) return 0; - struct v4l2_frequency freq; + struct v4l2_frequency freq = {0}; int rc = ioctl(sRadioFD, VIDIOC_G_FREQUENCY, &freq); if (rc < 0) { HAL_LOG("Could not get radio frequency"); diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index e87496bb25..a6f02ac993 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -297,6 +297,9 @@ public: static bool ShuttingDown() { return sShuttingDown; } +protected: + ~VibratorRunnable() {} + private: Monitor mMonitor; @@ -471,7 +474,7 @@ public: } // namespace -class BatteryObserver : public IUeventObserver +class BatteryObserver final : public IUeventObserver { public: NS_INLINE_DECL_REFCOUNTING(BatteryObserver) @@ -495,6 +498,9 @@ public: } } +protected: + ~BatteryObserver() {} + private: RefPtr mUpdater; }; @@ -603,6 +609,11 @@ void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) { int charge; + static bool previousCharging = false; + static double previousLevel = 0.0, remainingTime = 0.0; + static struct timespec lastLevelChange; + struct timespec now; + double dtime, dlevel; if (GetCurrentBatteryCharge(&charge)) { aBatteryInfo->level() = (double)charge / 100.0; @@ -618,11 +629,81 @@ GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) aBatteryInfo->charging() = true; } - if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) { + if (aBatteryInfo->charging() != previousCharging){ aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } else { - aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; + memset(&lastLevelChange, 0, sizeof(struct timespec)); + remainingTime = 0.0; } + + if (aBatteryInfo->charging()) { + if (aBatteryInfo->level() == 1.0) { + aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; + } else if (aBatteryInfo->level() != previousLevel){ + if (lastLevelChange.tv_sec != 0) { + clock_gettime(CLOCK_MONOTONIC, &now); + dtime = now.tv_sec - lastLevelChange.tv_sec; + dlevel = aBatteryInfo->level() - previousLevel; + + if (dlevel <= 0.0) { + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } else { + remainingTime = (double) round(dtime / dlevel * (1.0 - aBatteryInfo->level())); + aBatteryInfo->remainingTime() = remainingTime; + } + + lastLevelChange = now; + } else { // lastLevelChange.tv_sec == 0 + clock_gettime(CLOCK_MONOTONIC, &lastLevelChange); + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } + + } else { + clock_gettime(CLOCK_MONOTONIC, &now); + dtime = now.tv_sec - lastLevelChange.tv_sec; + if (dtime < remainingTime) { + aBatteryInfo->remainingTime() = round(remainingTime - dtime); + } else { + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } + + } + + } else { + if (aBatteryInfo->level() == 0.0) { + aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; + } else if (aBatteryInfo->level() != previousLevel){ + if (lastLevelChange.tv_sec != 0) { + clock_gettime(CLOCK_MONOTONIC, &now); + dtime = now.tv_sec - lastLevelChange.tv_sec; + dlevel = previousLevel - aBatteryInfo->level(); + + if (dlevel <= 0.0) { + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } else { + remainingTime = (double) round(dtime / dlevel * aBatteryInfo->level()); + aBatteryInfo->remainingTime() = remainingTime; + } + + lastLevelChange = now; + } else { // lastLevelChange.tv_sec == 0 + clock_gettime(CLOCK_MONOTONIC, &lastLevelChange); + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } + + } else { + clock_gettime(CLOCK_MONOTONIC, &now); + dtime = now.tv_sec - lastLevelChange.tv_sec; + if (dtime < remainingTime) { + aBatteryInfo->remainingTime() = round(remainingTime - dtime); + } else { + aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; + } + + } + } + + previousCharging = aBatteryInfo->charging(); + previousLevel = aBatteryInfo->level(); } namespace { @@ -662,8 +743,11 @@ bool GetKeyLightEnabled() { LightConfiguration config; - GetLight(eHalLightID_Buttons, &config); - return (config.color != 0x00000000); + bool ok = GetLight(eHalLightID_Buttons, &config); + if (ok) { + return (config.color != 0x00000000); + } + return false; } void @@ -696,10 +780,15 @@ GetScreenBrightness() LightConfiguration config; LightType light = eHalLightID_Backlight; - GetLight(light, &config); - // backlight is brightness only, so using one of the RGB elements as value. - int brightness = config.color & 0xFF; - return brightness / 255.0; + bool ok = GetLight(light, &config); + if (ok) { + // backlight is brightness only, so using one of the RGB elements as value. + int brightness = config.color & 0xFF; + return brightness / 255.0; + } + // If GetLight fails, it's because the light doesn't exist. So return + // a value corresponding to "off". + return 0; } void @@ -1152,6 +1241,10 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER + +protected: + ~OomVictimLogger() {} + private: double mLastLineChecked; ScopedFreePtr mRegexes; @@ -1541,8 +1634,12 @@ PriorityClass::PriorityClass(ProcessPriority aPriority) PriorityClass::~PriorityClass() { - close(mCpuCGroupProcsFd); - close(mMemCGroupProcsFd); + if (mCpuCGroupProcsFd != -1) { + close(mCpuCGroupProcsFd); + } + if (mMemCGroupProcsFd != -1) { + close(mMemCGroupProcsFd); + } } PriorityClass::PriorityClass(const PriorityClass& aOther) diff --git a/hal/gonk/GonkSensor.cpp b/hal/gonk/GonkSensor.cpp index 9f94e9b692..f361e064be 100644 --- a/hal/gonk/GonkSensor.cpp +++ b/hal/gonk/GonkSensor.cpp @@ -18,10 +18,14 @@ #include #include "mozilla/DebugOnly.h" +#include "mozilla/Saturate.h" #include "base/basictypes.h" #include "base/thread.h" +#include "GonkSensorsInterface.h" +#include "GonkSensorsPollInterface.h" +#include "GonkSensorsRegistryInterface.h" #include "Hal.h" #include "HalLog.h" #include "HalSensor.h" @@ -32,6 +36,10 @@ using namespace mozilla::hal; namespace mozilla { +// +// Internal implementation +// + // The value from SensorDevice.h (Android) #define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/ // ProcessOrientation.cpp needs smaller poll rate to detect delay between @@ -285,8 +293,8 @@ SetSensorState(SensorType aSensor, bool activate) } } -void -EnableSensorNotifications(SensorType aSensor) +static void +EnableSensorNotificationsInternal(SensorType aSensor) { if (!sSensorModule) { hw_get_module(SENSORS_HARDWARE_MODULE_ID, @@ -322,8 +330,8 @@ EnableSensorNotifications(SensorType aSensor) SetSensorState(aSensor, true); } -void -DisableSensorNotifications(SensorType aSensor) +static void +DisableSensorNotificationsInternal(SensorType aSensor) { if (!sSensorModule) { return; @@ -331,5 +339,522 @@ DisableSensorNotifications(SensorType aSensor) SetSensorState(aSensor, false); } +// +// Daemon +// + +typedef detail::SaturateOp SaturateOpUint32; + +/** + * The poll notification handler receives all events about sensors and + * sensor events. + */ +class SensorsPollNotificationHandler final + : public GonkSensorsPollNotificationHandler +{ +public: + SensorsPollNotificationHandler(GonkSensorsPollInterface* aPollInterface) + : mPollInterface(aPollInterface) + { + MOZ_ASSERT(mPollInterface); + + mPollInterface->SetNotificationHandler(this); + } + + void EnableSensorsByType(SensorsType aType) + { + if (SaturateOpUint32(mClasses[aType].mActivated)++) { + return; + } + + SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); + + // Old ref-count for the sensor type was 0, so we + // activate all sensors of the type. + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mType == aType && + mSensors[i].mDeliveryMode == deliveryMode) { + mPollInterface->EnableSensor(mSensors[i].mId, nullptr); + mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), + nullptr); + } + } + } + + void DisableSensorsByType(SensorsType aType) + { + if (SaturateOpUint32(mClasses[aType].mActivated)-- != 1) { + return; + } + + SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); + + // Old ref-count for the sensor type was 1, so we + // deactivate all sensors of the type. + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mType == aType && + mSensors[i].mDeliveryMode == deliveryMode) { + mPollInterface->DisableSensor(mSensors[i].mId, nullptr); + } + } + } + + void ClearSensorClasses() + { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mClasses); ++i) { + mClasses[i] = SensorsSensorClass(); + } + } + + void ClearSensors() + { + mSensors.Clear(); + } + + // Methods for SensorsPollNotificationHandler + // + + void ErrorNotification(SensorsError aError) override + { + // XXX: Bug 1206056: Try to repair some of the errors or restart cleanly. + } + + void SensorDetectedNotification(int32_t aId, SensorsType aType, + float aRange, float aResolution, + float aPower, int32_t aMinPeriod, + int32_t aMaxPeriod, + SensorsTriggerMode aTriggerMode, + SensorsDeliveryMode aDeliveryMode) override + { + auto i = FindSensorIndexById(aId); + if (i == -1) { + // Add a new sensor... + i = mSensors.Length(); + mSensors.AppendElement(SensorsSensor(aId, aType, aRange, aResolution, + aPower, aMinPeriod, aMaxPeriod, + aTriggerMode, aDeliveryMode)); + } else { + // ...or update an existing one. + mSensors[i] = SensorsSensor(aId, aType, aRange, aResolution, aPower, + aMinPeriod, aMaxPeriod, aTriggerMode, + aDeliveryMode); + } + + mClasses[aType].UpdateFromSensor(mSensors[i]); + + if (mClasses[aType].mActivated && + mSensors[i].mDeliveryMode == DefaultSensorsDeliveryMode(aType)) { + // The new sensor's type is enabled, so enable sensor. + mPollInterface->EnableSensor(aId, nullptr); + mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), + nullptr); + } + } + + void SensorLostNotification(int32_t aId) override + { + auto i = FindSensorIndexById(aId); + if (i != -1) { + mSensors.RemoveElementAt(i); + } + } + + void EventNotification(int32_t aId, const SensorsEvent& aEvent) override + { + auto i = FindSensorIndexById(aId); + if (i == -1) { + HAL_ERR("Sensor %d not registered", aId); + return; + } + + SensorData sensorData; + auto rv = CreateSensorData(aEvent, mClasses[mSensors[i].mType], + sensorData); + if (NS_FAILED(rv)) { + return; + } + + NotifySensorChange(sensorData); + } + +private: + ssize_t FindSensorIndexById(int32_t aId) const + { + for (size_t i = 0; i < mSensors.Length(); ++i) { + if (mSensors[i].mId == aId) { + return i; + } + } + return -1; + } + + uint64_t DefaultSensorPeriod(SensorsType aType) const + { + return aType == SENSORS_TYPE_ACCELEROMETER ? ACCELEROMETER_POLL_RATE + : DEFAULT_DEVICE_POLL_RATE; + } + + SensorsDeliveryMode DefaultSensorsDeliveryMode(SensorsType aType) const + { + if (aType == SENSORS_TYPE_PROXIMITY || + aType == SENSORS_TYPE_SIGNIFICANT_MOTION) { + return SENSORS_DELIVERY_MODE_IMMEDIATE; + } + return SENSORS_DELIVERY_MODE_BEST_EFFORT; + } + + SensorType HardwareSensorToHalSensor(SensorsType aType) const + { + // FIXME: bug 802004, add proper support for the magnetic-field sensor. + switch (aType) { + case SENSORS_TYPE_ORIENTATION: + return SENSOR_ORIENTATION; + case SENSORS_TYPE_ACCELEROMETER: + return SENSOR_ACCELERATION; + case SENSORS_TYPE_PROXIMITY: + return SENSOR_PROXIMITY; + case SENSORS_TYPE_LIGHT: + return SENSOR_LIGHT; + case SENSORS_TYPE_GYROSCOPE: + return SENSOR_GYROSCOPE; + case SENSORS_TYPE_LINEAR_ACCELERATION: + return SENSOR_LINEAR_ACCELERATION; + case SENSORS_TYPE_ROTATION_VECTOR: + return SENSOR_ROTATION_VECTOR; + case SENSORS_TYPE_GAME_ROTATION_VECTOR: + return SENSOR_GAME_ROTATION_VECTOR; + default: + NS_NOTREACHED("Invalid sensors type"); + } + return SENSOR_UNKNOWN; + } + + SensorAccuracyType HardwareStatusToHalAccuracy(SensorsStatus aStatus) const + { + return static_cast(aStatus - 1); + } + + nsresult CreateSensorData(const SensorsEvent& aEvent, + const SensorsSensorClass& aSensorClass, + SensorData& aSensorData) const + { + AutoTArray sensorValues; + + auto sensor = HardwareSensorToHalSensor(aEvent.mType); + + if (sensor == SENSOR_UNKNOWN) { + return NS_ERROR_ILLEGAL_VALUE; + } + + aSensorData.sensor() = sensor; + aSensorData.accuracy() = HardwareStatusToHalAccuracy(aEvent.mStatus); + aSensorData.timestamp() = aEvent.mTimestamp; + + if (aSensorData.sensor() == SENSOR_ORIENTATION) { + // Bug 938035: transfer HAL data for orientation sensor to meet W3C spec + // ex: HAL report alpha=90 means East but alpha=90 means West in W3C spec + sensorValues.AppendElement(360.0 - radToDeg(aEvent.mData.mFloat[0])); + sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[1])); + sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[2])); + } else if (aSensorData.sensor() == SENSOR_ACCELERATION) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + } else if (aSensorData.sensor() == SENSOR_PROXIMITY) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aSensorClass.mMinValue); + sensorValues.AppendElement(aSensorClass.mMaxValue); + } else if (aSensorData.sensor() == SENSOR_LINEAR_ACCELERATION) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + } else if (aSensorData.sensor() == SENSOR_GYROSCOPE) { + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[0])); + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[1])); + sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[2])); + } else if (aSensorData.sensor() == SENSOR_LIGHT) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + } else if (aSensorData.sensor() == SENSOR_ROTATION_VECTOR) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + sensorValues.AppendElement(aEvent.mData.mFloat[3]); + } else if (aSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) { + sensorValues.AppendElement(aEvent.mData.mFloat[0]); + sensorValues.AppendElement(aEvent.mData.mFloat[1]); + sensorValues.AppendElement(aEvent.mData.mFloat[2]); + sensorValues.AppendElement(aEvent.mData.mFloat[3]); + } + + aSensorData.values() = sensorValues; + + return NS_OK; + } + + GonkSensorsPollInterface* mPollInterface; + nsTArray mSensors; + SensorsSensorClass mClasses[SENSORS_NUM_TYPES]; +}; + +static StaticAutoPtr sPollNotificationHandler; + +/** + * This is the notifiaction handler for the Sensors interface. If the backend + * crashes, we can restart it from here. + */ +class SensorsNotificationHandler final : public GonkSensorsNotificationHandler +{ +public: + SensorsNotificationHandler(GonkSensorsInterface* aInterface) + : mInterface(aInterface) + { + MOZ_ASSERT(mInterface); + + mInterface->SetNotificationHandler(this); + } + + void BackendErrorNotification(bool aCrashed) override + { + // XXX: Bug 1206056: restart sensorsd + } + +private: + GonkSensorsInterface* mInterface; +}; + +static StaticAutoPtr sNotificationHandler; + +/** + * |SensorsRegisterModuleResultHandler| implements the result-handler + * callback for registering the Poll service and activating the first + * sensors. If an error occures during the process, the result handler + * disconnects and closes the backend. + */ +class SensorsRegisterModuleResultHandler final + : public GonkSensorsRegistryResultHandler +{ +public: + SensorsRegisterModuleResultHandler( + uint32_t* aSensorsTypeActivated, + GonkSensorsInterface* aInterface) + : mSensorsTypeActivated(aSensorsTypeActivated) + , mInterface(aInterface) + { + MOZ_ASSERT(mSensorsTypeActivated); + MOZ_ASSERT(mInterface); + } + void OnError(SensorsError aError) override + { + GonkSensorsRegistryResultHandler::OnError(aError); // print error message + Disconnect(); // Registering failed, so close the connection completely + } + void RegisterModule(uint32_t aProtocolVersion) override + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!sPollNotificationHandler); + + // Init, step 3: set notification handler for poll service and vice versa + auto pollInterface = mInterface->GetSensorsPollInterface(); + if (!pollInterface) { + Disconnect(); + return; + } + if (NS_FAILED(pollInterface->SetProtocolVersion(aProtocolVersion))) { + Disconnect(); + return; + } + + sPollNotificationHandler = + new SensorsPollNotificationHandler(pollInterface); + + // Init, step 4: activate sensors + for (int i = 0; i < SENSORS_NUM_TYPES; ++i) { + while (mSensorsTypeActivated[i]) { + sPollNotificationHandler->EnableSensorsByType( + static_cast(i)); + --mSensorsTypeActivated[i]; + } + } + } +public: + void Disconnect() + { + class DisconnectResultHandler final : public GonkSensorsResultHandler + { + public: + void OnError(SensorsError aError) + { + GonkSensorsResultHandler::OnError(aError); // print error message + sNotificationHandler = nullptr; + } + void Disconnect() override + { + sNotificationHandler = nullptr; + } + }; + mInterface->Disconnect(new DisconnectResultHandler()); + } +private: + uint32_t* mSensorsTypeActivated; + GonkSensorsInterface* mInterface; +}; + +/** + * |SensorsConnectResultHandler| implements the result-handler + * callback for starting the Sensors backend. + */ +class SensorsConnectResultHandler final : public GonkSensorsResultHandler +{ +public: + SensorsConnectResultHandler( + uint32_t* aSensorsTypeActivated, + GonkSensorsInterface* aInterface) + : mSensorsTypeActivated(aSensorsTypeActivated) + , mInterface(aInterface) + { + MOZ_ASSERT(mSensorsTypeActivated); + MOZ_ASSERT(mInterface); + } + void OnError(SensorsError aError) override + { + GonkSensorsResultHandler::OnError(aError); // print error message + sNotificationHandler = nullptr; + } + void Connect() override + { + MOZ_ASSERT(NS_IsMainThread()); + + // Init, step 2: register poll service + auto registryInterface = mInterface->GetSensorsRegistryInterface(); + if (!registryInterface) { + return; + } + registryInterface->RegisterModule( + GonkSensorsPollModule::SERVICE_ID, + new SensorsRegisterModuleResultHandler(mSensorsTypeActivated, + mInterface)); + } +private: + uint32_t* mSensorsTypeActivated; + GonkSensorsInterface* mInterface; +}; + +static uint32_t sSensorsTypeActivated[SENSORS_NUM_TYPES]; + +static const SensorsType sSensorsType[] = { + [SENSOR_ORIENTATION] = SENSORS_TYPE_ORIENTATION, + [SENSOR_ACCELERATION] = SENSORS_TYPE_ACCELEROMETER, + [SENSOR_PROXIMITY] = SENSORS_TYPE_PROXIMITY, + [SENSOR_LINEAR_ACCELERATION] = SENSORS_TYPE_LINEAR_ACCELERATION, + [SENSOR_GYROSCOPE] = SENSORS_TYPE_GYROSCOPE, + [SENSOR_LIGHT] = SENSORS_TYPE_LIGHT, + [SENSOR_ROTATION_VECTOR] = SENSORS_TYPE_ROTATION_VECTOR, + [SENSOR_GAME_ROTATION_VECTOR] = SENSORS_TYPE_GAME_ROTATION_VECTOR +}; + +void +EnableSensorNotificationsDaemon(SensorType aSensor) +{ + if ((aSensor < 0) || + (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) { + HAL_ERR("Sensor type %d not known", aSensor); + return; // Unsupported sensor type + } + + auto interface = GonkSensorsInterface::GetInstance(); + if (!interface) { + return; + } + + if (sPollNotificationHandler) { + // Everythings already up and running; enable sensor type. + sPollNotificationHandler->EnableSensorsByType(sSensorsType[aSensor]); + return; + } + + ++SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); + + if (sNotificationHandler) { + // We are in the middle of a pending start up; nothing else to do. + return; + } + + // Start up + + MOZ_ASSERT(!sPollNotificationHandler); + MOZ_ASSERT(!sNotificationHandler); + + sNotificationHandler = new SensorsNotificationHandler(interface); + + // Init, step 1: connect to Sensors backend + interface->Connect( + sNotificationHandler, + new SensorsConnectResultHandler(sSensorsTypeActivated, interface)); +} + +void +DisableSensorNotificationsDaemon(SensorType aSensor) +{ + if ((aSensor < 0) || + (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) { + HAL_ERR("Sensor type %d not known", aSensor); + return; // Unsupported sensor type + } + + if (sPollNotificationHandler) { + // Everthings up and running; disable sensors type + sPollNotificationHandler->DisableSensorsByType(sSensorsType[aSensor]); + return; + } + + // We might be in the middle of a startup; decrement type's ref-counter. + --SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); + + // TODO: stop sensorsd if all sensors are disabled +} + +// +// Public interface +// + +// TODO: Remove in-Gecko sensors code. Until all devices' base +// images come with sensorsd installed, we have to support the +// in-Gecko implementation as well. So we test for the existance +// of the binary. If it's there, we use it. Otherwise we run the +// old code. +static bool +HasDaemon() +{ + static bool tested; + static bool hasDaemon; + + if (MOZ_UNLIKELY(!tested)) { + hasDaemon = !access("/system/bin/sensorsd", X_OK); + tested = true; + } + + return hasDaemon; +} + +void +EnableSensorNotifications(SensorType aSensor) +{ + if (HasDaemon()) { + EnableSensorNotificationsDaemon(aSensor); + } else { + EnableSensorNotificationsInternal(aSensor); + } +} + +void +DisableSensorNotifications(SensorType aSensor) +{ + if (HasDaemon()) { + DisableSensorNotificationsDaemon(aSensor); + } else { + DisableSensorNotificationsInternal(aSensor); + } +} + } // hal_impl } // mozilla diff --git a/hal/gonk/GonkSensorsInterface.cpp b/hal/gonk/GonkSensorsInterface.cpp new file mode 100644 index 0000000000..c6c7658065 --- /dev/null +++ b/hal/gonk/GonkSensorsInterface.cpp @@ -0,0 +1,494 @@ +/* -*- 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 "GonkSensorsInterface.h" +#include "GonkSensorsPollInterface.h" +#include "GonkSensorsRegistryInterface.h" +#include "HalLog.h" +#include +#include +#include + +namespace mozilla { +namespace hal { + +using namespace mozilla::ipc; + +// +// GonkSensorsResultHandler +// + +void +GonkSensorsResultHandler::OnError(SensorsError aError) +{ + HAL_ERR("Received error code %d", static_cast(aError)); +} + +void +GonkSensorsResultHandler::Connect() +{ } + +void +GonkSensorsResultHandler::Disconnect() +{ } + +GonkSensorsResultHandler::~GonkSensorsResultHandler() +{ } + +// +// GonkSensorsNotificationHandler +// + +void +GonkSensorsNotificationHandler::BackendErrorNotification(bool aCrashed) +{ + if (aCrashed) { + HAL_ERR("Sensors backend crashed"); + } else { + HAL_ERR("Error in sensors backend"); + } +} + +GonkSensorsNotificationHandler::~GonkSensorsNotificationHandler() +{ } + +// +// GonkSensorsProtocol +// + +class GonkSensorsProtocol final + : public DaemonSocketIOConsumer + , public GonkSensorsRegistryModule + , public GonkSensorsPollModule +{ +public: + GonkSensorsProtocol(); + + void SetConnection(DaemonSocket* aConnection); + + already_AddRefed FetchResultHandler( + const DaemonSocketPDUHeader& aHeader); + + // Methods for |SensorsRegistryModule| and |SensorsPollModule| + // + + nsresult Send(DaemonSocketPDU* aPDU, + DaemonSocketResultHandler* aRes) override; + + // Methods for |DaemonSocketIOConsumer| + // + + void Handle(DaemonSocketPDU& aPDU) override; + void StoreResultHandler(const DaemonSocketPDU& aPDU) override; + +private: + void HandleRegistrySvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes); + void HandlePollSvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes); + + DaemonSocket* mConnection; + nsTArray> mResultHandlerQ; +}; + +GonkSensorsProtocol::GonkSensorsProtocol() +{ } + +void +GonkSensorsProtocol::SetConnection(DaemonSocket* aConnection) +{ + mConnection = aConnection; +} + +already_AddRefed +GonkSensorsProtocol::FetchResultHandler(const DaemonSocketPDUHeader& aHeader) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + if (aHeader.mOpcode & 0x80) { + return nullptr; // Ignore notifications + } + + RefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + + return res.forget(); +} + +void +GonkSensorsProtocol::HandleRegistrySvc( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + GonkSensorsRegistryModule::HandleSvc(aHeader, aPDU, aRes); +} + +void +GonkSensorsProtocol::HandlePollSvc( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + GonkSensorsPollModule::HandleSvc(aHeader, aPDU, aRes); +} + +// |SensorsRegistryModule|, |SensorsPollModule| + +nsresult +GonkSensorsProtocol::Send(DaemonSocketPDU* aPDU, + DaemonSocketResultHandler* aRes) +{ + MOZ_ASSERT(mConnection); + MOZ_ASSERT(aPDU); + + aPDU->SetConsumer(this); + aPDU->SetResultHandler(aRes); + aPDU->UpdateHeader(); + + if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) { + HAL_ERR("Sensors socket is disconnected"); + return NS_ERROR_FAILURE; + } + + mConnection->SendSocketData(aPDU); // Forward PDU to data channel + + return NS_OK; +} + +// |DaemonSocketIOConsumer| + +void +GonkSensorsProtocol::Handle(DaemonSocketPDU& aPDU) +{ + static void (GonkSensorsProtocol::* const HandleSvc[])( + const DaemonSocketPDUHeader&, DaemonSocketPDU&, + DaemonSocketResultHandler*) = { + [GonkSensorsRegistryModule::SERVICE_ID] = + &GonkSensorsProtocol::HandleRegistrySvc, + [GonkSensorsPollModule::SERVICE_ID] = + &GonkSensorsProtocol::HandlePollSvc + }; + + DaemonSocketPDUHeader header; + + if (NS_FAILED(UnpackPDU(aPDU, header))) { + return; + } + if (!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc)) || + !HandleSvc[header.mService]) { + HAL_ERR("Sensors service %d unknown", header.mService); + return; + } + + RefPtr res = FetchResultHandler(header); + + (this->*(HandleSvc[header.mService]))(header, aPDU, res); +} + +void +GonkSensorsProtocol::StoreResultHandler(const DaemonSocketPDU& aPDU) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + mResultHandlerQ.AppendElement(aPDU.GetResultHandler()); +} + +// +// GonkSensorsInterface +// + +GonkSensorsInterface* +GonkSensorsInterface::GetInstance() +{ + static GonkSensorsInterface* sGonkSensorsInterface; + + if (sGonkSensorsInterface) { + return sGonkSensorsInterface; + } + + sGonkSensorsInterface = new GonkSensorsInterface(); + + return sGonkSensorsInterface; +} + +void +GonkSensorsInterface::SetNotificationHandler( + GonkSensorsNotificationHandler* aNotificationHandler) +{ + MOZ_ASSERT(NS_IsMainThread()); + + mNotificationHandler = aNotificationHandler; +} + +/* + * The connect procedure consists of several steps. + * + * (1) Start listening for the command channel's socket connection: We + * do this before anything else, so that we don't miss connection + * requests from the Sensors daemon. This step will create a listen + * socket. + * + * (2) Start the Sensors daemon: When the daemon starts up it will open + * a socket connection to Gecko and thus create the data channel. + * Gecko already opened the listen socket in step (1). Step (2) ends + * with the creation of the data channel. + * + * (3) Signal success to the caller. + * + * If any step fails, we roll-back the procedure and signal an error to the + * caller. + */ +void +GonkSensorsInterface::Connect(GonkSensorsNotificationHandler* aNotificationHandler, + GonkSensorsResultHandler* aRes) +{ +#define BASE_SOCKET_NAME "sensorsd" + static unsigned long POSTFIX_LENGTH = 16; + + // If we could not cleanup properly before and an old + // instance of the daemon is still running, we kill it + // here. + mozilla::hal::StopSystemService("sensorsd"); + + mNotificationHandler = aNotificationHandler; + + mResultHandlerQ.AppendElement(aRes); + + if (!mProtocol) { + mProtocol = new GonkSensorsProtocol(); + } + + if (!mListenSocket) { + mListenSocket = new ListenSocket(this, LISTEN_SOCKET); + } + + // Init, step 1: Listen for data channel... */ + + if (!mDataSocket) { + mDataSocket = new DaemonSocket(mProtocol, this, DATA_SOCKET); + } else if (mDataSocket->GetConnectionStatus() == SOCKET_CONNECTED) { + // Command channel should not be open; let's close it. + mDataSocket->Close(); + } + + // The listen socket's name is generated with a random postfix. This + // avoids naming collisions if we still have a listen socket from a + // previously failed cleanup. It also makes it hard for malicious + // external programs to capture the socket name or connect before + // the daemon can do so. If no random postfix can be generated, we + // simply use the base name as-is. + nsresult rv = DaemonSocketConnector::CreateRandomAddressString( + NS_LITERAL_CSTRING(BASE_SOCKET_NAME), POSTFIX_LENGTH, mListenSocketName); + if (NS_FAILED(rv)) { + mListenSocketName.AssignLiteral(BASE_SOCKET_NAME); + } + + rv = mListenSocket->Listen(new DaemonSocketConnector(mListenSocketName), + mDataSocket); + if (NS_FAILED(rv)) { + OnConnectError(DATA_SOCKET); + return; + } + + // The protocol implementation needs a data channel for + // sending commands to the daemon. We set it here, because + // this is the earliest time when it's available. + mProtocol->SetConnection(mDataSocket); +} + +/* + * Disconnecting is inverse to connecting. + * + * (1) Close data socket: We close the data channel and the daemon will + * will notice. Once we see the socket's disconnect, we continue with + * the cleanup. + * + * (2) Close listen socket: The listen socket is not active any longer + * and we simply close it. + * + * (3) Signal success to the caller. + * + * We don't have to stop the daemon explicitly. It will cleanup and quit + * after it noticed the closing of the data channel + * + * Rolling back half-completed cleanups is not possible. In the case of + * an error, we simply push forward and try to recover during the next + * initialization. + */ +void +GonkSensorsInterface::Disconnect(GonkSensorsResultHandler* aRes) +{ + mNotificationHandler = nullptr; + + // Cleanup, step 1: Close data channel + mDataSocket->Close(); + + mResultHandlerQ.AppendElement(aRes); +} + +GonkSensorsRegistryInterface* +GonkSensorsInterface::GetSensorsRegistryInterface() +{ + if (mRegistryInterface) { + return mRegistryInterface; + } + + mRegistryInterface = new GonkSensorsRegistryInterface(mProtocol); + + return mRegistryInterface; +} + +GonkSensorsPollInterface* +GonkSensorsInterface::GetSensorsPollInterface() +{ + if (mPollInterface) { + return mPollInterface; + } + + mPollInterface = new GonkSensorsPollInterface(mProtocol); + + return mPollInterface; +} + +GonkSensorsInterface::GonkSensorsInterface() + : mNotificationHandler(nullptr) +{ } + +GonkSensorsInterface::~GonkSensorsInterface() +{ } + +void +GonkSensorsInterface::DispatchError(GonkSensorsResultHandler* aRes, + SensorsError aError) +{ + DaemonResultRunnable1::Dispatch( + aRes, &GonkSensorsResultHandler::OnError, + ConstantInitOp1(aError)); +} + +void +GonkSensorsInterface::DispatchError( + GonkSensorsResultHandler* aRes, nsresult aRv) +{ + SensorsError error; + + if (NS_FAILED(Convert(aRv, error))) { + error = SENSORS_ERROR_FAIL; + } + DispatchError(aRes, error); +} + +// |DaemonSocketConsumer|, |ListenSocketConsumer| + +void +GonkSensorsInterface::OnConnectSuccess(int aIndex) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); + + switch (aIndex) { + case LISTEN_SOCKET: { + // Init, step 2: Start Sensors daemon + nsCString args("-a "); + args.Append(mListenSocketName); + mozilla::hal::StartSystemService("sensorsd", args.get()); + } + break; + case DATA_SOCKET: + if (!mResultHandlerQ.IsEmpty()) { + // Init, step 3: Signal success + RefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + if (res) { + res->Connect(); + } + } + break; + } +} + +void +GonkSensorsInterface::OnConnectError(int aIndex) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); + + switch (aIndex) { + case DATA_SOCKET: + // Stop daemon and close listen socket + mozilla::hal::StopSystemService("sensorsd"); + mListenSocket->Close(); + // fall through + case LISTEN_SOCKET: + if (!mResultHandlerQ.IsEmpty()) { + // Signal error to caller + RefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + if (res) { + DispatchError(res, SENSORS_ERROR_FAIL); + } + } + break; + } +} + +/* + * Disconnects can happend + * + * (a) during startup, + * (b) during regular service, or + * (c) during shutdown. + * + * For cases (a) and (c), |mResultHandlerQ| contains an element. For + * case (b) |mResultHandlerQ| will be empty. This distinguishes a crash in + * the daemon. The following procedure to recover from crashes consists of + * several steps for case (b). + * + * (1) Close listen socket. + * (2) Wait for all sockets to be disconnected and inform caller about + * the crash. + * (3) After all resources have been cleaned up, let the caller restart + * the daemon. + */ +void +GonkSensorsInterface::OnDisconnect(int aIndex) +{ + MOZ_ASSERT(NS_IsMainThread()); + + switch (aIndex) { + case DATA_SOCKET: + // Cleanup, step 2 (Recovery, step 1): Close listen socket + mListenSocket->Close(); + break; + case LISTEN_SOCKET: + // Cleanup, step 3: Signal success to caller + if (!mResultHandlerQ.IsEmpty()) { + RefPtr res = mResultHandlerQ.ElementAt(0); + mResultHandlerQ.RemoveElementAt(0); + if (res) { + res->Disconnect(); + } + } + break; + } + + /* For recovery make sure all sockets disconnected, in order to avoid + * the remaining disconnects interfere with the restart procedure. + */ + if (mNotificationHandler && mResultHandlerQ.IsEmpty()) { + if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED && + mDataSocket->GetConnectionStatus() == SOCKET_DISCONNECTED) { + // Recovery, step 2: Notify the caller to prepare the restart procedure. + mNotificationHandler->BackendErrorNotification(true); + mNotificationHandler = nullptr; + } + } +} + +} // namespace hal +} // namespace mozilla diff --git a/hal/gonk/GonkSensorsInterface.h b/hal/gonk/GonkSensorsInterface.h new file mode 100644 index 0000000000..44126ce876 --- /dev/null +++ b/hal/gonk/GonkSensorsInterface.h @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * The sensors interface gives you access to the low-level sensors code + * in a platform-independent manner. The interfaces in this file allow + * for starting an stopping the sensors driver. Specific functionality + * is implemented in sub-interfaces. + */ + +#ifndef hal_gonk_GonkSensorsInterface_h +#define hal_gonk_GonkSensorsInterface_h + +#include +#include +#include +#include "SensorsTypes.h" + +namespace mozilla { +namespace ipc { + +class DaemonSocket; +class ListenSocket; + +} +} + +namespace mozilla { +namespace hal { + +class GonkSensorsPollInterface; +class GonkSensorsProtocol; +class GonkSensorsRegistryInterface; + +/** + * This class is the result-handler interface for the Sensors + * interface. Methods always run on the main thread. + */ +class GonkSensorsResultHandler + : public mozilla::ipc::DaemonSocketResultHandler +{ +public: + + /** + * Called if a command failed. + * + * @param aError The error code. + */ + virtual void OnError(SensorsError aError); + + /** + * The callback method for |GonkSensorsInterface::Connect|. + */ + virtual void Connect(); + + /** + * The callback method for |GonkSensorsInterface::Connect|. + */ + virtual void Disconnect(); + +protected: + virtual ~GonkSensorsResultHandler(); +}; + +/** + * This is the notification-handler interface. Implement this classes + * methods to handle event and notifications from the sensors daemon. + * All methods run on the main thread. + */ +class GonkSensorsNotificationHandler +{ +public: + + /** + * This notification is called when the backend code fails + * unexpectedly. Save state in the high-level code and restart + * the driver. + * + * @param aCrash True is the sensors driver crashed. + */ + virtual void BackendErrorNotification(bool aCrashed); + +protected: + virtual ~GonkSensorsNotificationHandler(); +}; + +/** + * This class implements the public interface to the Sensors functionality + * and driver. Use |GonkSensorsInterface::GetInstance| to retrieve an instance. + * All methods run on the main thread. + */ +class GonkSensorsInterface final + : public mozilla::ipc::DaemonSocketConsumer + , public mozilla::ipc::ListenSocketConsumer +{ +public: + /** + * Returns an instance of the Sensors backend. This code can return + * |nullptr| if no Sensors backend is available. + * + * @return An instance of |GonkSensorsInterface|. + */ + static GonkSensorsInterface* GetInstance(); + + /** + * This method sets the notification handler for sensor notifications. Call + * this method immediately after retreiving an instance of the class, or you + * won't be able able to receive notifications. You may not free the handler + * class while the Sensors backend is connected. + * + * @param aNotificationHandler An instance of a notification handler. + */ + void SetNotificationHandler( + GonkSensorsNotificationHandler* aNotificationHandler); + + /** + * This method starts the Sensors backend and establishes ad connection + * with Gecko. This is a multi-step process and errors are signalled by + * |GonkSensorsNotificationHandler::BackendErrorNotification|. If you see + * this notification before the connection has been established, it's + * certainly best to assume the Sensors backend to be not evailable. + * + * @param aRes The result handler. + */ + void Connect(GonkSensorsNotificationHandler* aNotificationHandler, + GonkSensorsResultHandler* aRes); + + /** + * This method disconnects Gecko from the Sensors backend and frees + * the backend's resources. This will invalidate all interfaces and + * state. Don't use any sensors functionality without reconnecting + * first. + * + * @param aRes The result handler. + */ + void Disconnect(GonkSensorsResultHandler* aRes); + + /** + * Returns the Registry interface for the connected Sensors backend. + * + * @return An instance of the Sensors Registry interface. + */ + GonkSensorsRegistryInterface* GetSensorsRegistryInterface(); + + /** + * Returns the Poll interface for the connected Sensors backend. + * + * @return An instance of the Sensors Poll interface. + */ + GonkSensorsPollInterface* GetSensorsPollInterface(); + +private: + enum Channel { + LISTEN_SOCKET, + DATA_SOCKET + }; + + GonkSensorsInterface(); + ~GonkSensorsInterface(); + + void DispatchError(GonkSensorsResultHandler* aRes, SensorsError aError); + void DispatchError(GonkSensorsResultHandler* aRes, nsresult aRv); + + // Methods for |DaemonSocketConsumer| and |ListenSocketConsumer| + // + + void OnConnectSuccess(int aIndex) override; + void OnConnectError(int aIndex) override; + void OnDisconnect(int aIndex) override; + + nsCString mListenSocketName; + RefPtr mListenSocket; + RefPtr mDataSocket; + nsAutoPtr mProtocol; + + nsTArray > mResultHandlerQ; + + GonkSensorsNotificationHandler* mNotificationHandler; + + nsAutoPtr mRegistryInterface; + nsAutoPtr mPollInterface; +}; + +} // namespace hal +} // namespace mozilla + +#endif // hal_gonk_GonkSensorsInterface_h diff --git a/hal/gonk/GonkSensorsPollInterface.cpp b/hal/gonk/GonkSensorsPollInterface.cpp new file mode 100644 index 0000000000..010deb656a --- /dev/null +++ b/hal/gonk/GonkSensorsPollInterface.cpp @@ -0,0 +1,430 @@ +/* -*- 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 "GonkSensorsPollInterface.h" +#include "HalLog.h" + +namespace mozilla { +namespace hal { + +using namespace mozilla::ipc; + +// +// GonkSensorsPollResultHandler +// + +void +GonkSensorsPollResultHandler::OnError(SensorsError aError) +{ + HAL_ERR("Received error code %d", static_cast(aError)); +} + +void +GonkSensorsPollResultHandler::EnableSensor() +{ } + +void +GonkSensorsPollResultHandler::DisableSensor() +{ } + +void +GonkSensorsPollResultHandler::SetPeriod() +{ } + +GonkSensorsPollResultHandler::~GonkSensorsPollResultHandler() +{ } + +// +// GonkSensorsPollNotificationHandler +// + +void +GonkSensorsPollNotificationHandler::ErrorNotification(SensorsError aError) +{ + HAL_ERR("Received error code %d", static_cast(aError)); +} + +void +GonkSensorsPollNotificationHandler::SensorDetectedNotification( + int32_t aId, + SensorsType aType, + float aRange, + float aResolution, + float aPower, + int32_t aMinPeriod, + int32_t aMaxPeriod, + SensorsTriggerMode aTriggerMode, + SensorsDeliveryMode aDeliveryMode) +{ } + +void +GonkSensorsPollNotificationHandler::SensorLostNotification(int32_t aId) +{ } + +void +GonkSensorsPollNotificationHandler::EventNotification(int32_t aId, + const SensorsEvent& aEvent) +{ } + +GonkSensorsPollNotificationHandler::~GonkSensorsPollNotificationHandler() +{ } + +// +// GonkSensorsPollModule +// + +GonkSensorsPollModule::GonkSensorsPollModule() + : mProtocolVersion(0) +{ } + +GonkSensorsPollModule::~GonkSensorsPollModule() +{ } + +nsresult +GonkSensorsPollModule::SetProtocolVersion(unsigned long aProtocolVersion) +{ + if ((aProtocolVersion < MIN_PROTOCOL_VERSION) || + (aProtocolVersion > MAX_PROTOCOL_VERSION)) { + HAL_ERR("Sensors Poll protocol version %lu not supported", + aProtocolVersion); + return NS_ERROR_ILLEGAL_VALUE; + } + mProtocolVersion = aProtocolVersion; + return NS_OK; +} + +void +GonkSensorsPollModule::HandleSvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + static void (GonkSensorsPollModule::* const HandleOp[])( + const DaemonSocketPDUHeader&, DaemonSocketPDU&, + DaemonSocketResultHandler*) = { + [0] = &GonkSensorsPollModule::HandleRsp, + [1] = &GonkSensorsPollModule::HandleNtf + }; + + MOZ_ASSERT(!NS_IsMainThread()); // I/O thread + + // Negate twice to map bit to 0/1 + unsigned long isNtf = !!(aHeader.mOpcode & 0x80); + + (this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes); +} + +// Commands +// + +nsresult +GonkSensorsPollModule::EnableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu( + new DaemonSocketPDU(SERVICE_ID, OPCODE_ENABLE_SENSOR, 0)); + + nsresult rv = PackPDU(aId, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + Unused << pdu.forget(); + return NS_OK; +} + +nsresult +GonkSensorsPollModule::DisableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu( + new DaemonSocketPDU(SERVICE_ID, OPCODE_DISABLE_SENSOR, 0)); + + nsresult rv = PackPDU(aId, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + Unused << pdu.forget(); + return NS_OK; +} + +nsresult +GonkSensorsPollModule::SetPeriodCmd(int32_t aId, uint64_t aPeriod, + GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu( + new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_PERIOD, 0)); + + nsresult rv = PackPDU(aId, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = PackPDU(aPeriod, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + Unused << pdu.forget(); + return NS_OK; +} + +// Responses +// + +void +GonkSensorsPollModule::ErrorRsp( + const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, GonkSensorsPollResultHandler* aRes) +{ + ErrorRunnable::Dispatch( + aRes, &GonkSensorsPollResultHandler::OnError, UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::EnableSensorRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, &GonkSensorsPollResultHandler::EnableSensor, UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::DisableSensorRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, &GonkSensorsPollResultHandler::DisableSensor, UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::SetPeriodRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, &GonkSensorsPollResultHandler::SetPeriod, UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::HandleRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + static void (GonkSensorsPollModule::* const sHandleRsp[])( + const DaemonSocketPDUHeader&, DaemonSocketPDU&, + GonkSensorsPollResultHandler*) = { + [OPCODE_ERROR] = &GonkSensorsPollModule::ErrorRsp, + [OPCODE_ENABLE_SENSOR] = &GonkSensorsPollModule::EnableSensorRsp, + [OPCODE_DISABLE_SENSOR] = &GonkSensorsPollModule::DisableSensorRsp, + [OPCODE_SET_PERIOD] = &GonkSensorsPollModule::SetPeriodRsp, + }; + + MOZ_ASSERT(!NS_IsMainThread()); // I/O thread + + if (!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(sHandleRsp)) || + !sHandleRsp[aHeader.mOpcode]) { + HAL_ERR("Sensors poll response opcode %d unknown", aHeader.mOpcode); + return; + } + + RefPtr res = + static_cast(aRes); + + if (!res) { + return; // Return early if no result handler has been set for response + } + + (this->*(sHandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res); +} + +// Notifications +// + +// Returns the current notification handler to a notification runnable +class GonkSensorsPollModule::NotificationHandlerWrapper final +{ +public: + typedef GonkSensorsPollNotificationHandler ObjectType; + + static ObjectType* GetInstance() + { + MOZ_ASSERT(NS_IsMainThread()); + + return sNotificationHandler; + } + + static GonkSensorsPollNotificationHandler* sNotificationHandler; +}; + +GonkSensorsPollNotificationHandler* + GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler; + +void +GonkSensorsPollModule::ErrorNtf( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) +{ + ErrorNotification::Dispatch( + &GonkSensorsPollNotificationHandler::ErrorNotification, + UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::SensorDetectedNtf( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) +{ + SensorDetectedNotification::Dispatch( + &GonkSensorsPollNotificationHandler::SensorDetectedNotification, + UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::SensorLostNtf( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) +{ + SensorLostNotification::Dispatch( + &GonkSensorsPollNotificationHandler::SensorLostNotification, + UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::EventNtf( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) +{ + EventNotification::Dispatch( + &GonkSensorsPollNotificationHandler::EventNotification, + UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsPollModule::HandleNtf( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + static void (GonkSensorsPollModule::* const sHandleNtf[])( + const DaemonSocketPDUHeader&, DaemonSocketPDU&) = { + [0] = &GonkSensorsPollModule::ErrorNtf, + [1] = &GonkSensorsPollModule::SensorDetectedNtf, + [2] = &GonkSensorsPollModule::SensorLostNtf, + [3] = &GonkSensorsPollModule::EventNtf + }; + + MOZ_ASSERT(!NS_IsMainThread()); + + uint8_t index = aHeader.mOpcode - 0x80; + + if (!(index < MOZ_ARRAY_LENGTH(sHandleNtf)) || !sHandleNtf[index]) { + HAL_ERR("Sensors poll notification opcode %d unknown", aHeader.mOpcode); + return; + } + + (this->*(sHandleNtf[index]))(aHeader, aPDU); +} + +// +// GonkSensorsPollInterface +// + +GonkSensorsPollInterface::GonkSensorsPollInterface( + GonkSensorsPollModule* aModule) + : mModule(aModule) +{ } + +GonkSensorsPollInterface::~GonkSensorsPollInterface() +{ } + +void +GonkSensorsPollInterface::SetNotificationHandler( + GonkSensorsPollNotificationHandler* aNotificationHandler) +{ + MOZ_ASSERT(NS_IsMainThread()); + + GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler = + aNotificationHandler; +} + +nsresult +GonkSensorsPollInterface::SetProtocolVersion(unsigned long aProtocolVersion) +{ + MOZ_ASSERT(mModule); + + return mModule->SetProtocolVersion(aProtocolVersion); +} + +void +GonkSensorsPollInterface::EnableSensor(int32_t aId, + GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(mModule); + + nsresult rv = mModule->EnableSensorCmd(aId, aRes); + if (NS_FAILED(rv)) { + DispatchError(aRes, rv); + } +} + +void +GonkSensorsPollInterface::DisableSensor(int32_t aId, + GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(mModule); + + nsresult rv = mModule->DisableSensorCmd(aId, aRes); + if (NS_FAILED(rv)) { + DispatchError(aRes, rv); + } +} + +void +GonkSensorsPollInterface::SetPeriod(int32_t aId, uint64_t aPeriod, + GonkSensorsPollResultHandler* aRes) +{ + MOZ_ASSERT(mModule); + + nsresult rv = mModule->SetPeriodCmd(aId, aPeriod, aRes); + if (NS_FAILED(rv)) { + DispatchError(aRes, rv); + } +} + +void +GonkSensorsPollInterface::DispatchError( + GonkSensorsPollResultHandler* aRes, SensorsError aError) +{ + DaemonResultRunnable1::Dispatch( + aRes, &GonkSensorsPollResultHandler::OnError, + ConstantInitOp1(aError)); +} + +void +GonkSensorsPollInterface::DispatchError( + GonkSensorsPollResultHandler* aRes, nsresult aRv) +{ + SensorsError error; + + if (NS_FAILED(Convert(aRv, error))) { + error = SENSORS_ERROR_FAIL; + } + DispatchError(aRes, error); +} + +} // namespace hal +} // namespace mozilla diff --git a/hal/gonk/GonkSensorsPollInterface.h b/hal/gonk/GonkSensorsPollInterface.h new file mode 100644 index 0000000000..d25fed4f3e --- /dev/null +++ b/hal/gonk/GonkSensorsPollInterface.h @@ -0,0 +1,343 @@ +/* -*- 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/. */ + +/* + * The poll interface gives yo access to the Sensors daemon's Poll service, + * which handles sensors. The poll service will inform you when sensors are + * detected or removed from the system. You can activate (or deactivate) + * existing sensors and poll will deliver the sensors' events. + * + * All public methods and callback methods run on the main thread. + */ + +#ifndef hal_gonk_GonkSensorsPollInterface_h +#define hal_gonk_GonkSensorsPollInterface_h + +#include +#include +#include "SensorsTypes.h" + +namespace mozilla { +namespace ipc { + +class DaemonSocketPDU; +class DaemonSocketPDUHeader; + +} +} + +namespace mozilla { +namespace hal { + +class SensorsInterface; + +using mozilla::ipc::DaemonSocketPDU; +using mozilla::ipc::DaemonSocketPDUHeader; +using mozilla::ipc::DaemonSocketResultHandler; + +/** + * This class is the result-handler interface for the Sensors + * Poll interface. Methods always run on the main thread. + */ +class GonkSensorsPollResultHandler : public DaemonSocketResultHandler +{ +public: + + /** + * Called if a poll command failed. + * + * @param aError The error code. + */ + virtual void OnError(SensorsError aError); + + /** + * The callback method for |GonkSensorsPollInterface::EnableSensor|. + */ + virtual void EnableSensor(); + + /** + * The callback method for |GonkSensorsPollInterface::DisableSensor|. + */ + virtual void DisableSensor(); + + /** + * The callback method for |GonkSensorsPollInterface::SetPeriod|. + */ + virtual void SetPeriod(); + +protected: + virtual ~GonkSensorsPollResultHandler(); +}; + +/** + * This is the notification-handler interface. Implement this classes + * methods to handle event and notifications from the sensors daemon. + */ +class GonkSensorsPollNotificationHandler +{ +public: + + /** + * The notification handler for errors. You'll receive this call if + * there's been a critical error in the daemon. Either try to handle + * the error, or restart the daemon. + * + * @param aError The error code. + */ + virtual void ErrorNotification(SensorsError aError); + + /** + * This methods gets call when a new sensor has been detected. + * + * @param aId The sensor's id. + * @param aType The sensor's type. + * @param aRange The sensor's maximum value. + * @param aResolution The minimum difference between two consecutive values. + * @param aPower The sensor's power consumption (in mA). + * @param aMinPeriod The minimum time between two events (in ns). + * @param aMaxPeriod The maximum time between two events (in ns). + * @param aTriggerMode The sensor's mode for triggering events. + * @param aDeliveryMode The sensor's urgency for event delivery. + */ + virtual void SensorDetectedNotification(int32_t aId, SensorsType aType, + float aRange, float aResolution, + float aPower, int32_t aMinPeriod, + int32_t aMaxPeriod, + SensorsTriggerMode aTriggerMode, + SensorsDeliveryMode aDeliveryMode); + + /** + * This methods gets call when an existing sensor has been removed. + * + * @param aId The sensor's id. + */ + virtual void SensorLostNotification(int32_t aId); + + /** + * This is the callback methods for sensor events. Only activated sensors + * generate events. All sensors are disabled by default. The actual data + * of the event depends on the sensor type. + * + * @param aId The sensor's id. + * @param aEvent The event's data. + */ + virtual void EventNotification(int32_t aId, const SensorsEvent& aEvent); + +protected: + virtual ~GonkSensorsPollNotificationHandler(); +}; + +/** + * This is the module class for the Sensors poll component. It handles PDU + * packing and unpacking. Methods are either executed on the main thread or + * the I/O thread. + * + * This is an internal class, use |GonkSensorsPollInterface| instead. + */ +class GonkSensorsPollModule +{ +public: + class NotificationHandlerWrapper; + + enum { + SERVICE_ID = 0x01 + }; + + enum { + OPCODE_ERROR = 0x00, + OPCODE_ENABLE_SENSOR = 0x01, + OPCODE_DISABLE_SENSOR = 0x02, + OPCODE_SET_PERIOD = 0x03 + }; + + enum { + MIN_PROTOCOL_VERSION = 1, + MAX_PROTOCOL_VERSION = 1 + }; + + virtual nsresult Send(DaemonSocketPDU* aPDU, + DaemonSocketResultHandler* aRes) = 0; + + nsresult SetProtocolVersion(unsigned long aProtocolVersion); + + // + // Commands + // + + nsresult EnableSensorCmd(int32_t aId, + GonkSensorsPollResultHandler* aRes); + + nsresult DisableSensorCmd(int32_t aId, + GonkSensorsPollResultHandler* aRes); + + nsresult SetPeriodCmd(int32_t aId, uint64_t aPeriod, + GonkSensorsPollResultHandler* aRes); + +protected: + GonkSensorsPollModule(); + virtual ~GonkSensorsPollModule(); + + void HandleSvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes); + +private: + + // + // Responses + // + + typedef mozilla::ipc::DaemonResultRunnable0< + GonkSensorsPollResultHandler, void> + ResultRunnable; + + typedef mozilla::ipc::DaemonResultRunnable1< + GonkSensorsPollResultHandler, void, SensorsError, SensorsError> + ErrorRunnable; + + void ErrorRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes); + + void EnableSensorRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes); + + void DisableSensorRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes); + + void SetPeriodRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsPollResultHandler* aRes); + + void HandleRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes); + + // + // Notifications + // + + typedef mozilla::ipc::DaemonNotificationRunnable1< + NotificationHandlerWrapper, void, SensorsError> + ErrorNotification; + + typedef mozilla::ipc::DaemonNotificationRunnable9< + NotificationHandlerWrapper, void, int32_t, SensorsType, + float, float, float, int32_t, int32_t, SensorsTriggerMode, + SensorsDeliveryMode> + SensorDetectedNotification; + + typedef mozilla::ipc::DaemonNotificationRunnable1< + NotificationHandlerWrapper, void, int32_t> + SensorLostNotification; + + typedef mozilla::ipc::DaemonNotificationRunnable2< + NotificationHandlerWrapper, void, int32_t, SensorsEvent, int32_t, + const SensorsEvent&> + EventNotification; + + class SensorDetectedInitOp; + class SensorLostInitOp; + class EventInitOp; + + void ErrorNtf(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU); + + void SensorDetectedNtf(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU); + + void SensorLostNtf(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU); + + void EventNtf(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU); + + void HandleNtf(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes); + +private: + unsigned long mProtocolVersion; +}; + +/** + * This class implements the public interface to the Sensors poll + * component. Use |SensorsInterface::GetPollInterface| to retrieve + * an instance. All methods run on the main thread. + */ +class GonkSensorsPollInterface final +{ +public: + friend class GonkSensorsInterface; + + /** + * This method sets the notification handler for poll notifications. Call + * this method immediately after registering the module. Otherwise you won't + * be able able to receive poll notifications. You may not free the handler + * class while the poll component is regsitered. + * + * @param aNotificationHandler An instance of a poll notification handler. + */ + void SetNotificationHandler( + GonkSensorsPollNotificationHandler* aNotificationHandler); + + /** + * This method sets the protocol version. You should set it to the + * value that has been returned from the backend when registering the + * Poll service. You cannot send or receive messages before setting + * the protocol version. + * + * @param aProtocolVersion + * @return NS_OK for supported versions, or an XPCOM error code otherwise. + */ + nsresult SetProtocolVersion(unsigned long aProtocolVersion); + + /** + * Enables an existing sensor. The sensor id will have been delivered in + * a SensorDetectedNotification. + * + * @param aId The sensor's id. + * @param aRes The result handler. + */ + void EnableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes); + + /** + * Disables an existing sensor. The sensor id will have been delivered in + * a SensorDetectedNotification. + * + * @param aId The sensor's id. + * @param aRes The result handler. + */ + void DisableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes); + + /** + * Sets the period for a sensor. The sensor id will have been delivered in + * a SensorDetectedNotification. The value for the period should be between + * the sensor's minimum and maximum period. + * + * @param aId The sensor's id. + * @param aPeriod The sensor's new period. + * @param aRes The result handler. + */ + void SetPeriod(int32_t aId, uint64_t aPeriod, GonkSensorsPollResultHandler* aRes); + + ~GonkSensorsPollInterface(); + +private: + GonkSensorsPollInterface(GonkSensorsPollModule* aModule); + + void DispatchError(GonkSensorsPollResultHandler* aRes, SensorsError aError); + void DispatchError(GonkSensorsPollResultHandler* aRes, nsresult aRv); + + GonkSensorsPollModule* mModule; +}; + +} // hal +} // namespace mozilla + +#endif // hal_gonk_GonkSensorsPollInterface_h diff --git a/hal/gonk/GonkSensorsRegistryInterface.cpp b/hal/gonk/GonkSensorsRegistryInterface.cpp new file mode 100644 index 0000000000..0fc318fe2a --- /dev/null +++ b/hal/gonk/GonkSensorsRegistryInterface.cpp @@ -0,0 +1,212 @@ +/* -*- 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 "GonkSensorsRegistryInterface.h" +#include "GonkSensorsHelpers.h" +#include "HalLog.h" + +namespace mozilla { +namespace hal { + +using namespace mozilla::ipc; + +// +// GonkSensorsRegistryResultHandler +// + +void +GonkSensorsRegistryResultHandler::OnError(SensorsError aError) +{ + HAL_ERR("Received error code %d", static_cast(aError)); +} + +void +GonkSensorsRegistryResultHandler::RegisterModule(uint32_t aProtocolVersion) +{ } + +void +GonkSensorsRegistryResultHandler::UnregisterModule() +{ } + +GonkSensorsRegistryResultHandler::~GonkSensorsRegistryResultHandler() +{ } + +// +// GonkSensorsRegistryModule +// + +GonkSensorsRegistryModule::~GonkSensorsRegistryModule() +{ } + +void +GonkSensorsRegistryModule::HandleSvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + DaemonSocketResultHandler* aRes) +{ + static void (GonkSensorsRegistryModule::* const HandleRsp[])( + const DaemonSocketPDUHeader&, + DaemonSocketPDU&, + GonkSensorsRegistryResultHandler*) = { + [OPCODE_ERROR] = &GonkSensorsRegistryModule::ErrorRsp, + [OPCODE_REGISTER_MODULE] = &GonkSensorsRegistryModule::RegisterModuleRsp, + [OPCODE_UNREGISTER_MODULE] = &GonkSensorsRegistryModule::UnregisterModuleRsp + }; + + if ((aHeader.mOpcode >= MOZ_ARRAY_LENGTH(HandleRsp)) || + !HandleRsp[aHeader.mOpcode]) { + HAL_ERR("Sensors registry response opcode %d unknown", aHeader.mOpcode); + return; + } + + RefPtr res = + static_cast(aRes); + + if (!res) { + return; // Return early if no result handler has been set + } + + (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res); +} + +// Commands +// + +nsresult +GonkSensorsRegistryModule::RegisterModuleCmd( + uint8_t aId, GonkSensorsRegistryResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu( + new DaemonSocketPDU(SERVICE_ID, OPCODE_REGISTER_MODULE, 0)); + + nsresult rv = PackPDU(aId, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + Unused << pdu.forget(); + return NS_OK; +} + +nsresult +GonkSensorsRegistryModule::UnregisterModuleCmd( + uint8_t aId, GonkSensorsRegistryResultHandler* aRes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsAutoPtr pdu( + new DaemonSocketPDU(SERVICE_ID, OPCODE_UNREGISTER_MODULE, 0)); + + nsresult rv = PackPDU(aId, *pdu); + if (NS_FAILED(rv)) { + return rv; + } + rv = Send(pdu, aRes); + if (NS_FAILED(rv)) { + return rv; + } + Unused << pdu.forget(); + return NS_OK; +} + +// Responses +// + +void +GonkSensorsRegistryModule::ErrorRsp( + const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, GonkSensorsRegistryResultHandler* aRes) +{ + ErrorRunnable::Dispatch( + aRes, &GonkSensorsRegistryResultHandler::OnError, UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsRegistryModule::RegisterModuleRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + GonkSensorsRegistryResultHandler* aRes) +{ + Uint32ResultRunnable::Dispatch( + aRes, + &GonkSensorsRegistryResultHandler::RegisterModule, + UnpackPDUInitOp(aPDU)); +} + +void +GonkSensorsRegistryModule::UnregisterModuleRsp( + const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, + GonkSensorsRegistryResultHandler* aRes) +{ + ResultRunnable::Dispatch( + aRes, + &GonkSensorsRegistryResultHandler::UnregisterModule, + UnpackPDUInitOp(aPDU)); +} + +// +// GonkSensorsRegistryInterface +// + +GonkSensorsRegistryInterface::GonkSensorsRegistryInterface( + GonkSensorsRegistryModule* aModule) + : mModule(aModule) +{ } + +GonkSensorsRegistryInterface::~GonkSensorsRegistryInterface() +{ } + +void +GonkSensorsRegistryInterface::RegisterModule( + uint8_t aId, GonkSensorsRegistryResultHandler* aRes) +{ + MOZ_ASSERT(mModule); + + nsresult rv = mModule->RegisterModuleCmd(aId, aRes); + if (NS_FAILED(rv)) { + DispatchError(aRes, rv); + } +} + +void +GonkSensorsRegistryInterface::UnregisterModule( + uint8_t aId, GonkSensorsRegistryResultHandler* aRes) +{ + MOZ_ASSERT(mModule); + + nsresult rv = mModule->UnregisterModuleCmd(aId, aRes); + if (NS_FAILED(rv)) { + DispatchError(aRes, rv); + } +} + +void +GonkSensorsRegistryInterface::DispatchError( + GonkSensorsRegistryResultHandler* aRes, SensorsError aError) +{ + DaemonResultRunnable1::Dispatch( + aRes, &GonkSensorsRegistryResultHandler::OnError, + ConstantInitOp1(aError)); +} + +void +GonkSensorsRegistryInterface::DispatchError( + GonkSensorsRegistryResultHandler* aRes, nsresult aRv) +{ + SensorsError error; + + if (NS_FAILED(Convert(aRv, error))) { + error = SENSORS_ERROR_FAIL; + } + DispatchError(aRes, error); +} + +} // namespace hal +} // namespace mozilla diff --git a/hal/gonk/GonkSensorsRegistryInterface.h b/hal/gonk/GonkSensorsRegistryInterface.h new file mode 100644 index 0000000000..e7d64cb1d8 --- /dev/null +++ b/hal/gonk/GonkSensorsRegistryInterface.h @@ -0,0 +1,185 @@ +/* -*- 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/. */ + +/* + * The registry interface gives yo access to the Sensors daemon's Registry + * service. The purpose of the service is to register and setup all other + * services, and make them available. + * + * All public methods and callback methods run on the main thread. + */ + +#ifndef hal_gonk_GonkSensorsRegistryInterface_h +#define hal_gonk_GonkSensorsRegistryInterface_h + +#include +#include +#include "SensorsTypes.h" + +namespace mozilla { +namespace ipc { + +class DaemonSocketPDU; +class DaemonSocketPDUHeader; + +} +} + +namespace mozilla { +namespace hal { + +class SensorsInterface; + +using mozilla::ipc::DaemonSocketPDU; +using mozilla::ipc::DaemonSocketPDUHeader; +using mozilla::ipc::DaemonSocketResultHandler; + +/** + * This class is the result-handler interface for the Sensors + * Registry interface. Methods always run on the main thread. + */ +class GonkSensorsRegistryResultHandler : public DaemonSocketResultHandler +{ +public: + + /** + * Called if a registry command failed. + * + * @param aError The error code. + */ + virtual void OnError(SensorsError aError); + + /** + * The callback method for |GonkSensorsRegistryInterface::RegisterModule|. + * + * @param aProtocolVersion The daemon's protocol version. Make sure it's + * compatible with Gecko's implementation. + */ + virtual void RegisterModule(uint32_t aProtocolVersion); + + /** + * The callback method for |SensorsRegsitryInterface::UnregisterModule|. + */ + virtual void UnregisterModule(); + +protected: + virtual ~GonkSensorsRegistryResultHandler(); +}; + +/** + * This is the module class for the Sensors registry component. It handles + * PDU packing and unpacking. Methods are either executed on the main thread + * or the I/O thread. + * + * This is an internal class, use |GonkSensorsRegistryInterface| instead. + */ +class GonkSensorsRegistryModule +{ +public: + enum { + SERVICE_ID = 0x00 + }; + + enum { + OPCODE_ERROR = 0x00, + OPCODE_REGISTER_MODULE = 0x01, + OPCODE_UNREGISTER_MODULE = 0x02 + }; + + virtual nsresult Send(DaemonSocketPDU* aPDU, + DaemonSocketResultHandler* aRes) = 0; + + // + // Commands + // + + nsresult RegisterModuleCmd(uint8_t aId, + GonkSensorsRegistryResultHandler* aRes); + + nsresult UnregisterModuleCmd(uint8_t aId, + GonkSensorsRegistryResultHandler* aRes); + +protected: + virtual ~GonkSensorsRegistryModule(); + + void HandleSvc(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes); + + // + // Responses + // + + typedef mozilla::ipc::DaemonResultRunnable0< + GonkSensorsRegistryResultHandler, void> + ResultRunnable; + + typedef mozilla::ipc::DaemonResultRunnable1< + GonkSensorsRegistryResultHandler, void, uint32_t, uint32_t> + Uint32ResultRunnable; + + typedef mozilla::ipc::DaemonResultRunnable1< + GonkSensorsRegistryResultHandler, void, SensorsError, SensorsError> + ErrorRunnable; + + void ErrorRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsRegistryResultHandler* aRes); + + void RegisterModuleRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsRegistryResultHandler* aRes); + + void UnregisterModuleRsp(const DaemonSocketPDUHeader& aHeader, + DaemonSocketPDU& aPDU, + GonkSensorsRegistryResultHandler* aRes); +}; + +/** + * This class implements the public interface to the Sensors Registry + * component. Use |SensorsInterface::GetRegistryInterface| to retrieve + * an instance. All methods run on the main thread. + */ +class GonkSensorsRegistryInterface final +{ +public: + friend class GonkSensorsInterface; + + /** + * Sends a RegisterModule command to the Sensors daemon. When the + * result handler's |RegisterModule| method gets called, the service + * has been registered successfully and can be used. + * + * @param aId The id of the service that is to be registered. + * @param aRes The result handler. + */ + void RegisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes); + + /** + * Sends an UnregisterModule command to the Sensors daemon. The service + * should not be used afterwards until it has been registered again. + * + * @param aId The id of the service that is to be unregistered. + * @param aRes The result handler. + */ + void UnregisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes); + + ~GonkSensorsRegistryInterface(); + +private: + GonkSensorsRegistryInterface(GonkSensorsRegistryModule* aModule); + + void DispatchError(GonkSensorsRegistryResultHandler* aRes, + SensorsError aError); + void DispatchError(GonkSensorsRegistryResultHandler* aRes, + nsresult aRv); + + GonkSensorsRegistryModule* mModule; +}; + +} // namespace hal +} // namespace mozilla + +#endif // hal_gonk_GonkSensorsRegistryInterface_h diff --git a/hal/gonk/GonkSwitch.cpp b/hal/gonk/GonkSwitch.cpp index b8863e5a1d..1e8ee81f71 100644 --- a/hal/gonk/GonkSwitch.cpp +++ b/hal/gonk/GonkSwitch.cpp @@ -61,10 +61,6 @@ public: GetInitialState(); } - virtual ~SwitchHandler() - { - } - bool CheckEvent(NetlinkEvent* aEvent) { if (strcmp(GetSubsystem(), aEvent->getSubsystem()) || @@ -86,6 +82,10 @@ public: return mDevice; } protected: + virtual ~SwitchHandler() + { + } + virtual const char* GetSubsystem() { return "switch"; diff --git a/hal/gonk/UeventPoller.cpp b/hal/gonk/UeventPoller.cpp index a33faf1ca3..d6d66191e6 100644 --- a/hal/gonk/UeventPoller.cpp +++ b/hal/gonk/UeventPoller.cpp @@ -31,13 +31,16 @@ #include "HalLog.h" #include "nsDebug.h" #include "base/message_loop.h" +#include "mozilla/ClearOnShutdown.h" #include "mozilla/FileUtils.h" -#include "nsAutoPtr.h" +#include "mozilla/Monitor.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" #include "UeventPoller.h" +using namespace mozilla; + namespace mozilla { namespace hal_impl { @@ -72,8 +75,9 @@ public: void UnregisterObserver(IUeventObserver *aObserver) { mUeventObserverList.RemoveObserver(aObserver); - if (mUeventObserverList.Length() == 0) + if (mUeventObserverList.Length() == 0) { ShutdownUevent(); // this will destroy self + } } private: @@ -92,13 +96,16 @@ bool NetlinkPoller::OpenSocket() { mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (mSocket.get() < 0) + if (mSocket.get() < 0) { return false; + } int sz = kBuffsize; - if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) + if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, + sizeof(sz)) < 0) { return false; + } // add FD_CLOEXEC flag int flags = fcntl(mSocket.get(), F_GETFD); @@ -106,12 +113,14 @@ NetlinkPoller::OpenSocket() return false; } flags |= FD_CLOEXEC; - if (fcntl(mSocket.get(), F_SETFD, flags) == -1) + if (fcntl(mSocket.get(), F_SETFD, flags) == -1) { return false; + } // set non-blocking - if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) + if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) { return false; + } struct sockaddr_nl saddr; bzero(&saddr, sizeof(saddr)); @@ -150,7 +159,7 @@ NetlinkPoller::OpenSocket() return true; } -static nsAutoPtr sPoller; +static StaticAutoPtr sPoller; class UeventInitTask : public Task { @@ -190,6 +199,69 @@ NetlinkPoller::OnFileCanReadWithoutBlocking(int fd) } } +static bool sShutdown = false; + +class ShutdownNetlinkPoller; +static StaticAutoPtr sShutdownPoller; +static Monitor* sMonitor = nullptr; + +class ShutdownNetlinkPoller { +public: + ~ShutdownNetlinkPoller() + { + // This is called from KillClearOnShutdown() on the main thread. + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetIOMessageLoop()); + + { + MonitorAutoLock lock(*sMonitor); + + XRE_GetIOMessageLoop()->PostTask( + FROM_HERE, + NewRunnableFunction(ShutdownUeventIOThread)); + + while (!sShutdown) { + lock.Wait(); + } + } + + sShutdown = true; + delete sMonitor; + } + + static void MaybeInit() + { + MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (sShutdown || sMonitor) { + // Don't init twice or init after shutdown. + return; + } + + sMonitor = new Monitor("ShutdownNetlinkPoller.monitor"); + { + ShutdownNetlinkPoller* shutdownPoller = new ShutdownNetlinkPoller(); + + nsCOMPtr runnable = NS_NewRunnableFunction([=] () -> void + { + sShutdownPoller = shutdownPoller; + ClearOnShutdown(&sShutdownPoller); // Must run on the main thread. + }); + MOZ_ASSERT(runnable); + MOZ_ALWAYS_TRUE(NS_SUCCEEDED( + NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))); + } + } +private: + ShutdownNetlinkPoller() = default; + static void ShutdownUeventIOThread() + { + MonitorAutoLock l(*sMonitor); + ShutdownUevent(); // Must run on the IO thread. + sShutdown = true; + l.NotifyAll(); + } +}; + static void InitializeUevent() { @@ -197,6 +269,7 @@ InitializeUevent() sPoller = new NetlinkPoller(); sPoller->GetIOLoop()->PostTask(FROM_HERE, new UeventInitTask()); + ShutdownNetlinkPoller::MaybeInit(); } static void @@ -210,8 +283,13 @@ RegisterUeventListener(IUeventObserver *aObserver) { MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (!sPoller) + if (sShutdown) { + return; + } + + if (!sPoller) { InitializeUevent(); + } sPoller->RegisterObserver(aObserver); } @@ -220,6 +298,10 @@ UnregisterUeventListener(IUeventObserver *aObserver) { MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); + if (sShutdown) { + return; + } + sPoller->UnregisterObserver(aObserver); } diff --git a/hal/linux/UPowerClient.cpp b/hal/linux/UPowerClient.cpp index 3b769099d9..410aaf3de5 100644 --- a/hal/linux/UPowerClient.cpp +++ b/hal/linux/UPowerClient.cpp @@ -7,6 +7,7 @@ #include "HalLog.h" #include #include +#include #include #include "nsAutoRef.h" #include @@ -417,6 +418,7 @@ UPowerClient::UpdateSavedInfo(GHashTable* aHashTable) break; case eState_FullyCharged: isFull = true; + MOZ_FALLTHROUGH; case eState_Charging: case eState_PendingCharge: mCharging = true; diff --git a/hal/moz.build b/hal/moz.build index b089f8e490..e3d46a695d 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -49,6 +49,9 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': 'gonk/GonkFMRadio.cpp', 'gonk/GonkSensor.cpp', 'gonk/GonkSensorsHelpers.cpp', + 'gonk/GonkSensorsInterface.cpp', + 'gonk/GonkSensorsPollInterface.cpp', + 'gonk/GonkSensorsRegistryInterface.cpp', 'gonk/GonkSwitch.cpp', 'gonk/SystemService.cpp', 'gonk/UeventPoller.cpp', diff --git a/intl/unicharutil/tools/genUnicodePropertyData.pl b/intl/unicharutil/tools/genUnicodePropertyData.pl index 41ee4358e6..126563cc08 100644 --- a/intl/unicharutil/tools/genUnicodePropertyData.pl +++ b/intl/unicharutil/tools/genUnicodePropertyData.pl @@ -40,8 +40,9 @@ # # (2) Run this tool using a command line of the form # -# perl genUnicodePropertyData.pl \ -# /path/to/harfbuzz/src \ +# perl genUnicodePropertyData.pl \ +# /path/to/harfbuzz/src \ +# /path/to/icu/common/unicode \ # /path/to/UCD-directory # # This will generate (or overwrite!) the files @@ -54,15 +55,17 @@ use strict; use List::Util qw(first); -if ($#ARGV != 1) { +if ($#ARGV != 2) { print <<__EOT; # Run this tool using a command line of the form # -# perl genUnicodePropertyData.pl \\ -# /path/to/harfbuzz/src \\ +# perl genUnicodePropertyData.pl \\ +# /path/to/harfbuzz/src \\ +# /path/to/icu/common/unicode \\ # /path/to/UCD-directory # # where harfbuzz/src is the directory containing harfbuzz .cc and .hh files, +# icu/common/unicode is the directory containing ICU 'common' public headers, # and UCD-directory is a directory containing the current Unicode Character # Database files (UnicodeData.txt, etc), available from # http://www.unicode.org/Public/UNIDATA/, with additional resources as @@ -78,190 +81,20 @@ __EOT exit 0; } -# load HB_Script and HB_Category constants +my $HARFBUZZ = $ARGV[0]; +my $ICU = $ARGV[1]; +my $UNICODE = $ARGV[2]; -# NOTE that HB_SCRIPT_* constants are now "tag" values, NOT sequentially-allocated -# script codes as used by Glib/Pango/etc. -# We therefore define a set of MOZ_SCRIPT_* constants that are script _codes_ -# compatible with those libraries, and map these to HB_SCRIPT_* _tags_ as needed. +# load HB_Category constants -# CHECK that this matches Pango source (as found for example at -# http://git.gnome.org/browse/pango/tree/pango/pango-script.h) -# for as many codes as that defines (currently up through Unicode 5.1) -# and the GLib enumeration -# http://developer.gnome.org/glib/2.30/glib-Unicode-Manipulation.html#GUnicodeScript -# (currently defined up through Unicode 6.0). -# Constants beyond these may be regarded as unstable for now, but we don't actually -# depend on the specific values. -my %scriptCode = ( - INVALID => -1, - COMMON => 0, - INHERITED => 1, - ARABIC => 2, - ARMENIAN => 3, - BENGALI => 4, - BOPOMOFO => 5, - CHEROKEE => 6, - COPTIC => 7, - CYRILLIC => 8, - DESERET => 9, - DEVANAGARI => 10, - ETHIOPIC => 11, - GEORGIAN => 12, - GOTHIC => 13, - GREEK => 14, - GUJARATI => 15, - GURMUKHI => 16, - HAN => 17, - HANGUL => 18, - HEBREW => 19, - HIRAGANA => 20, - KANNADA => 21, - KATAKANA => 22, - KHMER => 23, - LAO => 24, - LATIN => 25, - MALAYALAM => 26, - MONGOLIAN => 27, - MYANMAR => 28, - OGHAM => 29, - OLD_ITALIC => 30, - ORIYA => 31, - RUNIC => 32, - SINHALA => 33, - SYRIAC => 34, - TAMIL => 35, - TELUGU => 36, - THAANA => 37, - THAI => 38, - TIBETAN => 39, - CANADIAN_ABORIGINAL => 40, - YI => 41, - TAGALOG => 42, - HANUNOO => 43, - BUHID => 44, - TAGBANWA => 45, -# unicode 4.0 additions - BRAILLE => 46, - CYPRIOT => 47, - LIMBU => 48, - OSMANYA => 49, - SHAVIAN => 50, - LINEAR_B => 51, - TAI_LE => 52, - UGARITIC => 53, -# unicode 4.1 additions - NEW_TAI_LUE => 54, - BUGINESE => 55, - GLAGOLITIC => 56, - TIFINAGH => 57, - SYLOTI_NAGRI => 58, - OLD_PERSIAN => 59, - KHAROSHTHI => 60, -# unicode 5.0 additions - UNKNOWN => 61, - BALINESE => 62, - CUNEIFORM => 63, - PHOENICIAN => 64, - PHAGS_PA => 65, - NKO => 66, -# unicode 5.1 additions - KAYAH_LI => 67, - LEPCHA => 68, - REJANG => 69, - SUNDANESE => 70, - SAURASHTRA => 71, - CHAM => 72, - OL_CHIKI => 73, - VAI => 74, - CARIAN => 75, - LYCIAN => 76, - LYDIAN => 77, -# unicode 5.2 additions - AVESTAN => 78, - BAMUM => 79, - EGYPTIAN_HIEROGLYPHS => 80, - IMPERIAL_ARAMAIC => 81, - INSCRIPTIONAL_PAHLAVI => 82, - INSCRIPTIONAL_PARTHIAN => 83, - JAVANESE => 84, - KAITHI => 85, - LISU => 86, - MEETEI_MAYEK => 87, - OLD_SOUTH_ARABIAN => 88, - OLD_TURKIC => 89, - SAMARITAN => 90, - TAI_THAM => 91, - TAI_VIET => 92, -# unicode 6.0 additions - BATAK => 93, - BRAHMI => 94, - MANDAIC => 95, -# unicode 6.1 additions - CHAKMA => 96, - MEROITIC_CURSIVE => 97, - MEROITIC_HIEROGLYPHS => 98, - MIAO => 99, - SHARADA => 100, - SORA_SOMPENG => 101, - TAKRI => 102, -# unicode 7.0 additions - BASSA_VAH => 103, - CAUCASIAN_ALBANIAN => 104, - DUPLOYAN => 105, - ELBASAN => 106, - GRANTHA => 107, - KHOJKI => 108, - KHUDAWADI => 109, - LINEAR_A => 110, - MAHAJANI => 111, - MANICHAEAN => 112, - MENDE_KIKAKUI => 113, - MODI => 114, - MRO => 115, - NABATAEAN => 116, - OLD_NORTH_ARABIAN => 117, - OLD_PERMIC => 118, - PAHAWH_HMONG => 119, - PALMYRENE => 120, - PAU_CIN_HAU => 121, - PSALTER_PAHLAVI => 122, - SIDDHAM => 123, - TIRHUTA => 124, - WARANG_CITI => 125, -# unicode 8.0 additions - AHOM => 126, - ANATOLIAN_HIEROGLYPHS => 127, - HATRAN => 128, - MULTANI => 129, - OLD_HUNGARIAN => 130, - SIGNWRITING => 131, - -# additional "script" code, not from Unicode (but matches ISO 15924's Zmth tag) - MATHEMATICAL_NOTATION => 132, -); - -my $sc = -1; my $cc = -1; my %catCode; -my @scriptCodeToTag; -my @scriptCodeToName; sub readHarfBuzzHeader { my $file = shift; - open FH, "< $ARGV[0]/$file" or die "can't open harfbuzz header $ARGV[0]/$file\n"; + open FH, "< $HARFBUZZ/$file" or die "can't open harfbuzz header $HARFBUZZ/$file\n"; while () { - s/CANADIAN_SYLLABICS/CANADIAN_ABORIGINAL/; # harfbuzz and unicode disagree on this name :( - if (m/HB_SCRIPT_([A-Z_]+)\s*=\s*HB_TAG\s*\(('.','.','.','.')\)\s*,/) { - unless (exists $scriptCode{$1}) { - warn "unknown script name $1 found in $file\n"; - next; - } - $sc = $scriptCode{$1}; - $scriptCodeToTag[$sc] = $2; - $scriptCodeToName[$sc] = $1; - } if (m/HB_UNICODE_GENERAL_CATEGORY_([A-Z_]+)/) { $cc++; $catCode{$1} = $cc; @@ -270,16 +103,40 @@ sub readHarfBuzzHeader close FH; } -&readHarfBuzzHeader("hb-common.h"); &readHarfBuzzHeader("hb-unicode.h"); -die "didn't find HarfBuzz script codes\n" if $sc == -1; die "didn't find HarfBuzz category codes\n" if $cc == -1; -# Additional code not present in HarfBuzz headers: -$sc = $scriptCode{"MATHEMATICAL_NOTATION"}; -$scriptCodeToTag[$sc] = "'Z','m','t','h'"; -$scriptCodeToName[$sc] = "MATHEMATICAL_NOTATION"; +my %scriptCode; +my @scriptCodeToTag; +my @scriptCodeToName; + +my $sc = -1; + +sub readIcuHeader +{ + my $file = shift; + open FH, "< $ICU/$file" or die "can't open ICU header $ICU/$file\n"; + while () { + # adjust for ICU vs UCD naming discrepancies + s/LANNA/TAI_THAM/; + s/MEITEI_MAYEK/MEETEI_MAYEK/; + s/ORKHON/OLD_TURKIC/; + s/MENDE/MENDE_KIKAKUI/; + s/SIGN_WRITING/SIGNWRITING/; + if (m|USCRIPT_([A-Z_]+)\s*=\s*([0-9]+),\s*/\*\s*([A-Z][a-z]{3})\s*\*/|) { + $sc = $2; + $scriptCode{$1} = $sc; + $scriptCodeToTag[$sc] = $3; + $scriptCodeToName[$sc] = $1; + } + } + close FH; +} + +&readIcuHeader("uscript.h"); + +die "didn't find ICU script codes\n" if $sc == -1; my %xidmodCode = ( 'Recommended' => 0, @@ -317,9 +174,9 @@ my %bidicategoryCode = ( "PDF" => "16", # Pop Directional Format "NSM" => "17", # Non-Spacing Mark "BN" => "18", # Boundary Neutral - "LRI" => "19", # Left-to-Right Isolate - "RLI" => "20", # Right-to-left Isolate - "FSI" => "21", # First Strong Isolate + "FSI" => "19", # First Strong Isolate + "LRI" => "20", # Left-to-Right Isolate + "RLI" => "21", # Right-to-left Isolate "PDI" => "22" # Pop Direcitonal Isolate ); @@ -404,7 +261,7 @@ my %ucd2hb = ( # read ReadMe.txt my @versionInfo; -open FH, "< $ARGV[1]/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n"; +open FH, "< $UNICODE/ReadMe.txt" or die "can't open Unicode ReadMe.txt file\n"; while () { chomp; push @versionInfo, $_; @@ -418,7 +275,7 @@ my $kLowerToUpper = 0x10000000; my $kCaseMapCharMask = 0x001fffff; # read UnicodeData.txt -open FH, "< $ARGV[1]/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n"; +open FH, "< $UNICODE/UnicodeData.txt" or die "can't open UCD file UnicodeData.txt\n"; while () { chomp; my @fields = split /;/; @@ -490,7 +347,7 @@ while () { close FH; # read Scripts.txt -open FH, "< $ARGV[1]/Scripts.txt" or die "can't open UCD file Scripts.txt\n"; +open FH, "< $UNICODE/Scripts.txt" or die "can't open UCD file Scripts.txt\n"; push @versionInfo, ""; while () { chomp; @@ -500,8 +357,8 @@ while () { while () { if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))*\s+;\s+([^ ]+)/) { my $script = uc($3); - warn "unknown script $script" unless exists $scriptCode{$script}; - $script = $scriptCode{$script}; + warn "unknown ICU script $script" unless exists $scriptCode{$script}; + my $script = $scriptCode{$script}; my $start = hex "0x$1"; my $end = (defined $2) ? hex "0x$2" : $start; for (my $i = $start; $i <= $end; ++$i) { @@ -515,7 +372,7 @@ close FH; my @offsets = (); push @offsets, 0; -open FH, "< $ARGV[1]/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n"; +open FH, "< $UNICODE/BidiMirroring.txt" or die "can't open UCD file BidiMirroring.txt\n"; push @versionInfo, ""; while () { chomp; @@ -543,7 +400,7 @@ my %pairedBracketTypeCode = ( 'O' => 1, 'C' => 2 ); -open FH, "< $ARGV[1]/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n"; +open FH, "< $UNICODE/BidiBrackets.txt" or die "can't open UCD file BidiBrackets.txt\n"; push @versionInfo, ""; while () { chomp; @@ -570,7 +427,7 @@ my %hangulType = ( 'LV' => 0x03, 'LVT' => 0x07 ); -open FH, "< $ARGV[1]/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n"; +open FH, "< $UNICODE/HangulSyllableType.txt" or die "can't open UCD file HangulSyllableType.txt\n"; push @versionInfo, ""; while () { chomp; @@ -593,7 +450,7 @@ while () { close FH; # read xidmodifications.txt -open FH, "< $ARGV[1]/security/xidmodifications.txt" or die "can't open UCD file xidmodifications.txt\n"; +open FH, "< $UNICODE/security/xidmodifications.txt" or die "can't open UCD file xidmodifications.txt\n"; push @versionInfo, ""; while () { chomp; @@ -616,7 +473,7 @@ while () { } close FH; -open FH, "< $ARGV[1]/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n"; +open FH, "< $UNICODE/Unihan_Variants.txt" or die "can't open UCD file Unihan_Variants.txt (from Unihan.zip)\n"; push @versionInfo, ""; while () { chomp; @@ -653,7 +510,7 @@ while () { close FH; # read VerticalOrientation-13.txt -open FH, "< $ARGV[1]/vertical/VerticalOrientation-13.txt" or die "can't open UTR50 data file VerticalOrientation-13.txt\n"; +open FH, "< $UNICODE/vertical/VerticalOrientation-13.txt" or die "can't open UTR50 data file VerticalOrientation-13.txt\n"; push @versionInfo, ""; while () { chomp; @@ -732,21 +589,25 @@ $versionInfo __END +print DATA_TABLES "#if !ENABLE_INTL_API\n"; print DATA_TABLES "static const uint32_t sScriptCodeToTag[] = {\n"; for (my $i = 0; $i < scalar @scriptCodeToTag; ++$i) { - printf DATA_TABLES " HB_TAG(%s)", $scriptCodeToTag[$i]; + printf DATA_TABLES " HB_TAG('%c','%c','%c','%c')", unpack('cccc', $scriptCodeToTag[$i]); print DATA_TABLES $i < $#scriptCodeToTag ? ",\n" : "\n"; } -print DATA_TABLES "};\n\n"; +print DATA_TABLES "};\n"; +print DATA_TABLES "#endif\n\n"; our $totalData = 0; +print DATA_TABLES "#if !ENABLE_INTL_API\n"; print DATA_TABLES "static const int16_t sMirrorOffsets[] = {\n"; for (my $i = 0; $i < scalar @offsets; ++$i) { printf DATA_TABLES " $offsets[$i]"; print DATA_TABLES $i < $#offsets ? ",\n" : "\n"; } -print DATA_TABLES "};\n\n"; +print DATA_TABLES "};\n"; +print DATA_TABLES "#endif\n\n"; print HEADER "#pragma pack(1)\n\n"; @@ -762,11 +623,26 @@ struct nsCharProps1 { unsigned char mCombiningClass:8; }; /; -print DATA_TABLES "#ifndef ENABLE_INTL_API\n"; -&genTables("CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1); -print DATA_TABLES "#endif\n\n"; +&genTables("#if !ENABLE_INTL_API", "#endif", + "CharProp1", $type, "nsCharProps1", 11, 5, \&sprintCharProps1, 1, 2, 1); -sub sprintCharProps2 +sub sprintCharProps2_short +{ + my $usv = shift; + return sprintf("{%d,%d,%d},", + $pairedBracketType[$usv], $verticalOrientation[$usv], $xidmod[$usv]); +} +$type = q/ +struct nsCharProps2 { + unsigned char mPairedBracketType:2; + unsigned char mVertOrient:2; + unsigned char mXidmod:4; +}; +/; +&genTables("#if ENABLE_INTL_API", "#endif", + "CharProp2", $type, "nsCharProps2", 9, 7, \&sprintCharProps2_short, 16, 1, 1); + +sub sprintCharProps2_full { my $usv = shift; return sprintf("{%d,%d,%d,%d,%d,%d,%d},", @@ -785,7 +661,8 @@ struct nsCharProps2 { unsigned char mVertOrient:2; }; |; -&genTables("CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2, 16, 4, 1); +&genTables("#if !ENABLE_INTL_API", "#endif", + "CharProp2", $type, "nsCharProps2", 11, 5, \&sprintCharProps2_full, 16, 4, 1); print HEADER "#pragma pack()\n\n"; @@ -800,21 +677,22 @@ sub sprintHanVariants } return sprintf("0x%02x,", $val); } -&genTables("HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4); +## Han Variant data currently unused but may be needed in future, see bug 857481 +## &genTables("", "", "HanVariant", "", "uint8_t", 9, 7, \&sprintHanVariants, 2, 1, 4); sub sprintFullWidth { my $usv = shift; return sprintf("0x%04x,", $fullWidth[$usv]); } -&genTables("FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1); +&genTables("", "", "FullWidth", "", "uint16_t", 10, 6, \&sprintFullWidth, 0, 2, 1); sub sprintCasemap { my $usv = shift; return sprintf("0x%08x,", $casemap[$usv]); } -&genTables("CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1); +&genTables("", "", "CaseMap", "", "uint32_t", 11, 5, \&sprintCasemap, 1, 4, 1); print STDERR "Total data = $totalData\n"; @@ -826,8 +704,16 @@ printf DATA_TABLES "const uint32_t kCaseMapCharMask = 0x%08x;\n\n", $kCaseMapCha sub genTables { - my ($prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_; + my ($guardBegin, $guardEnd, + $prefix, $typedef, $type, $indexBits, $charBits, $func, $maxPlane, $bytesPerEntry, $charsPerEntry) = @_; + if ($typedef ne '') { + print HEADER "$guardBegin\n"; + print HEADER "$typedef\n"; + print HEADER "$guardEnd\n\n"; + } + + print DATA_TABLES "\n$guardBegin\n"; print DATA_TABLES "#define k${prefix}MaxPlane $maxPlane\n"; print DATA_TABLES "#define k${prefix}IndexBits $indexBits\n"; print DATA_TABLES "#define k${prefix}CharBits $charBits\n"; @@ -888,8 +774,6 @@ sub genTables } print DATA_TABLES "};\n\n"; - print HEADER "$typedef\n\n" if $typedef ne ''; - my $pageLen = $charsPerPage / $charsPerEntry; print DATA_TABLES "static const $type s${prefix}Values[$chCount][$pageLen] = {\n"; for (my $i = 0; $i < scalar @char; ++$i) { @@ -897,7 +781,8 @@ sub genTables print DATA_TABLES $char[$i]; print DATA_TABLES $i < $#char ? "},\n" : "}\n"; } - print DATA_TABLES "};\n\n"; + print DATA_TABLES "};\n"; + print DATA_TABLES "$guardEnd\n"; my $dataSize = $pmCount * $indexLen * $pmBits/8 + $chCount * $pageLen * $bytesPerEntry + diff --git a/intl/unicharutil/util/nsBidiUtils.h b/intl/unicharutil/util/nsBidiUtils.h index ce2ac307b8..f002dd508a 100644 --- a/intl/unicharutil/util/nsBidiUtils.h +++ b/intl/unicharutil/util/nsBidiUtils.h @@ -14,7 +14,8 @@ * for the detailed definition of the following categories * * The values here must match the equivalents in %bidicategorycode in - * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl + * mozilla/intl/unicharutil/tools/genUnicodePropertyData.pl, + * and must also match the values used by ICU's UCharDirection. */ enum nsCharType { @@ -37,9 +38,9 @@ enum nsCharType { eCharType_PopDirectionalFormat = 16, eCharType_DirNonSpacingMark = 17, eCharType_BoundaryNeutral = 18, - eCharType_LeftToRightIsolate = 19, - eCharType_RightToLeftIsolate = 20, - eCharType_FirstStrongIsolate = 21, + eCharType_FirstStrongIsolate = 19, + eCharType_LeftToRightIsolate = 20, + eCharType_RightToLeftIsolate = 21, eCharType_PopDirectionalIsolate = 22, eCharType_CharTypeCount }; diff --git a/intl/unicharutil/util/nsUnicodeProperties.cpp b/intl/unicharutil/util/nsUnicodeProperties.cpp index 22810e5f84..6beab3a967 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.cpp +++ b/intl/unicharutil/util/nsUnicodeProperties.cpp @@ -11,12 +11,12 @@ #if ENABLE_INTL_API #include "unicode/uchar.h" +#include "unicode/uscript.h" #endif #define UNICODE_BMP_LIMIT 0x10000 #define UNICODE_LIMIT 0x110000 - #ifndef ENABLE_INTL_API static const nsCharProps1& GetCharProps1(uint32_t aCh) @@ -56,14 +56,21 @@ GetCharProps2(uint32_t aCh) NS_NOTREACHED("Getting CharProps for codepoint outside Unicode range"); // Default values for unassigned + using namespace mozilla::unicode; static const nsCharProps2 undefined = { - MOZ_SCRIPT_UNKNOWN, // Script code - 0, // East Asian Width - HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // General Category - eCharType_LeftToRight, // Bidi Category - mozilla::unicode::XIDMOD_NOT_CHARS, // Xidmod - -1, // Numeric Value - mozilla::unicode::HVT_NotHan // Han variant +#if ENABLE_INTL_API + PAIRED_BRACKET_TYPE_NONE, + VERTICAL_ORIENTATION_R, + XIDMOD_NOT_CHARS +#else + MOZ_SCRIPT_UNKNOWN, + PAIRED_BRACKET_TYPE_NONE, + HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, + eCharType_LeftToRight, + XIDMOD_NOT_CHARS, + -1, // Numeric Value + VERTICAL_ORIENTATION_R +#endif }; return undefined; } @@ -93,7 +100,7 @@ to provide the most compact storage, depending on the distribution of values. */ -nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = { +const nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = { /* * The order here corresponds to the HB_UNICODE_GENERAL_CATEGORY_* constants * of the hb_unicode_general_category_t enum in gfx/harfbuzz/src/hb-unicode.h. @@ -130,6 +137,69 @@ nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[] = { /* SPACE_SEPARATOR */ nsIUGenCategory::kSeparator }; +#ifdef ENABLE_INTL_API +const hb_unicode_general_category_t sICUtoHBcategory[U_CHAR_CATEGORY_COUNT] = { + HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, // U_GENERAL_OTHER_TYPES = 0, + HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, // U_UPPERCASE_LETTER = 1, + HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, // U_LOWERCASE_LETTER = 2, + HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, // U_TITLECASE_LETTER = 3, + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, // U_MODIFIER_LETTER = 4, + HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, // U_OTHER_LETTER = 5, + HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, // U_NON_SPACING_MARK = 6, + HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, // U_ENCLOSING_MARK = 7, + HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, // U_COMBINING_SPACING_MARK = 8, + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, // U_DECIMAL_DIGIT_NUMBER = 9, + HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, // U_LETTER_NUMBER = 10, + HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, // U_OTHER_NUMBER = 11, + HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, // U_SPACE_SEPARATOR = 12, + HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, // U_LINE_SEPARATOR = 13, + HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, // U_PARAGRAPH_SEPARATOR = 14, + HB_UNICODE_GENERAL_CATEGORY_CONTROL, // U_CONTROL_CHAR = 15, + HB_UNICODE_GENERAL_CATEGORY_FORMAT, // U_FORMAT_CHAR = 16, + HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, // U_PRIVATE_USE_CHAR = 17, + HB_UNICODE_GENERAL_CATEGORY_SURROGATE, // U_SURROGATE = 18, + HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, // U_DASH_PUNCTUATION = 19, + HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, // U_START_PUNCTUATION = 20, + HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, // U_END_PUNCTUATION = 21, + HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, // U_CONNECTOR_PUNCTUATION = 22, + HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, // U_OTHER_PUNCTUATION = 23, + HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, // U_MATH_SYMBOL = 24, + HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, // U_CURRENCY_SYMBOL = 25, + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, // U_MODIFIER_SYMBOL = 26, + HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, // U_OTHER_SYMBOL = 27, + HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, // U_INITIAL_PUNCTUATION = 28, + HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, // U_FINAL_PUNCTUATION = 29, +}; +#endif + +uint8_t GetGeneralCategory(uint32_t aCh) { +#if ENABLE_INTL_API + return sICUtoHBcategory[u_charType(aCh)]; +#else + return GetCharProps2(aCh).mCategory; +#endif +} + +nsCharType GetBidiCat(uint32_t aCh) { +#if ENABLE_INTL_API + return nsCharType(u_charDirection(aCh)); +#else + return nsCharType(GetCharProps2(aCh).mBidiCategory); +#endif +} + +int8_t GetNumericValue(uint32_t aCh) { +#if ENABLE_INTL_API + UNumericType type = + UNumericType(u_getIntPropertyValue(aCh, UCHAR_NUMERIC_TYPE)); + return type == U_NT_DECIMAL || type == U_NT_DIGIT + ? int8_t(u_getNumericValue(aCh)) + : -1; +#else + return GetCharProps2(aCh).mNumericValue; +#endif +} + uint32_t GetMirroredChar(uint32_t aCh) { @@ -160,14 +230,30 @@ GetCombiningClass(uint32_t aCh) #endif } +uint8_t +GetScriptCode(uint32_t aCh) +{ +#if ENABLE_INTL_API + UErrorCode err = U_ZERO_ERROR; + return uscript_getScript(aCh, &err); +#else + return GetCharProps2(aCh).mScriptCode; +#endif +} + uint32_t GetScriptTagForCode(int32_t aScriptCode) { +#if ENABLE_INTL_API + const char* tag = uscript_getShortName(UScriptCode(aScriptCode)); + return HB_TAG(tag[0], tag[1], tag[2], tag[3]); +#else // this will safely return 0 for negative script codes, too :) if (uint32_t(aScriptCode) > ArrayLength(sScriptCodeToTag)) { return 0; } return sScriptCodeToTag[aScriptCode]; +#endif } PairedBracketType GetPairedBracketType(uint32_t aCh) @@ -254,6 +340,7 @@ GetTitlecaseForAll(uint32_t aCh) return aCh; } +#if 0 // currently unused - bug 857481 HanVariantType GetHanVariant(uint32_t aCh) { @@ -272,6 +359,7 @@ GetHanVariant(uint32_t aCh) // extract the appropriate 2-bit field from the value return HanVariantType((v >> ((aCh & 3) * 2)) & 3); } +#endif uint32_t GetFullWidth(uint32_t aCh) diff --git a/intl/unicharutil/util/nsUnicodeProperties.h b/intl/unicharutil/util/nsUnicodeProperties.h index 3abf660b0d..8bee5f847b 100644 --- a/intl/unicharutil/util/nsUnicodeProperties.h +++ b/intl/unicharutil/util/nsUnicodeProperties.h @@ -16,7 +16,7 @@ namespace mozilla { namespace unicode { -extern nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[]; +extern const nsIUGenCategory::nsUGenCategory sDetailedToGeneralCategory[]; // Return whether the char has a mirrored-pair counterpart. uint32_t GetMirroredChar(uint32_t aCh); @@ -26,25 +26,19 @@ bool HasMirroredChar(uint32_t aChr); uint8_t GetCombiningClass(uint32_t aCh); // returns the detailed General Category in terms of HB_UNICODE_* values -inline uint8_t GetGeneralCategory(uint32_t aCh) { - return GetCharProps2(aCh).mCategory; -} +uint8_t GetGeneralCategory(uint32_t aCh); // returns the simplified Gen Category as defined in nsIUGenCategory inline nsIUGenCategory::nsUGenCategory GetGenCategory(uint32_t aCh) { return sDetailedToGeneralCategory[GetGeneralCategory(aCh)]; } -inline uint8_t GetScriptCode(uint32_t aCh) { - return GetCharProps2(aCh).mScriptCode; -} +nsCharType GetBidiCat(uint32_t aCh); + +uint8_t GetScriptCode(uint32_t aCh); uint32_t GetScriptTagForCode(int32_t aScriptCode); -inline nsCharType GetBidiCat(uint32_t aCh) { - return nsCharType(GetCharProps2(aCh).mBidiCategory); -} - /* This MUST match the values assigned by genUnicodePropertyData.pl! */ enum VerticalOrientation { VERTICAL_ORIENTATION_U = 0, @@ -93,10 +87,9 @@ inline XidmodType GetIdentifierModification(uint32_t aCh) { * To restrict to decimal digits, the caller should also check whether * GetGeneralCategory returns HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER */ -inline int8_t GetNumericValue(uint32_t aCh) { - return GetCharProps2(aCh).mNumericValue; -} +int8_t GetNumericValue(uint32_t aCh); +#if 0 // currently unused - bug 857481 enum HanVariantType { HVT_NotHan = 0x0, HVT_SimplifiedOnly = 0x1, @@ -105,6 +98,7 @@ enum HanVariantType { }; HanVariantType GetHanVariant(uint32_t aCh); +#endif uint32_t GetFullWidth(uint32_t aCh); diff --git a/js/xpconnect/tests/chrome/test_bug853283.xul b/js/xpconnect/tests/chrome/test_bug853283.xul index 8275809bd5..ac59ad9a77 100644 --- a/js/xpconnect/tests/chrome/test_bug853283.xul +++ b/js/xpconnect/tests/chrome/test_bug853283.xul @@ -30,7 +30,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=853283 var sb = new Cu.Sandbox(window); sb.iwin = iwin; sb.ok = ok; - Cu.evalInSandbox('try {iwin.navigator.mozApps; ok(true, "Didnt throw"); } catch (e) { ok(false, "Threw: " + e);}', sb); + Cu.evalInSandbox('try {iwin.navigator.mozContacts; ok(true, "Didnt throw"); } catch (e) { ok(false, "Threw: " + e);}', sb); SimpleTest.finish(); } diff --git a/layout/generic/MathMLTextRunFactory.cpp b/layout/generic/MathMLTextRunFactory.cpp index 1fc3cb148a..3f7337f0d9 100644 --- a/layout/generic/MathMLTextRunFactory.cpp +++ b/layout/generic/MathMLTextRunFactory.cpp @@ -773,12 +773,15 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, } if (!child) return; + + typedef gfxTextRun::Range Range; + // Copy potential linebreaks into child so they're preserved // (and also child will be shaped appropriately) NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(), "Dropped characters or break-before values somewhere!"); - child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), - canBreakBeforeArray.Elements()); + Range range(0, uint32_t(canBreakBeforeArray.Length())); + child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements()); if (transformedChild) { transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR); } @@ -796,6 +799,6 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, // We can't steal the data because the child may be cached and stealing // the data would break the cache. aTextRun->ResetGlyphRuns(); - aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0); + aTextRun->CopyGlyphDataFrom(child, Range(child), 0); } } diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index 62e64a9345..28e89e0aa1 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -252,8 +252,8 @@ nsDisplayTextOverflowMarker::PaintTextToContext(nsRenderingContext* aCtx, NS_ASSERTION(!textRun->IsRightToLeft(), "Ellipsis textruns should always be LTR!"); gfxPoint gfxPt(pt.x, pt.y); - textRun->Draw(aCtx->ThebesContext(), gfxPt, DrawMode::GLYPH_FILL, - 0, textRun->GetLength(), nullptr, nullptr, nullptr); + textRun->Draw(gfxTextRun::Range(textRun), gfxPt, + gfxTextRun::DrawParams(aCtx->ThebesContext())); } } else { RefPtr fm; @@ -803,7 +803,7 @@ TextOverflow::Marker::SetupString(nsIFrame* aFrame) if (mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) { gfxTextRun* textRun = GetEllipsisTextRun(aFrame); if (textRun) { - mISize = textRun->GetAdvanceWidth(0, textRun->GetLength(), nullptr); + mISize = textRun->GetAdvanceWidth(); } else { mISize = 0; } diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index bf9fb2468e..8ca8493845 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -979,8 +979,9 @@ public: virtual void SetBreaks(uint32_t aOffset, uint32_t aLength, uint8_t* aBreakBefore) override { - if (mTextRun->SetPotentialLineBreaks(aOffset + mOffsetIntoTextRun, aLength, - aBreakBefore)) { + gfxTextRun::Range range(aOffset + mOffsetIntoTextRun, + aOffset + mOffsetIntoTextRun + aLength); + if (mTextRun->SetPotentialLineBreaks(range, aBreakBefore)) { // Be conservative and assume that some breaks have been set mTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_NO_BREAKS); } @@ -2927,18 +2928,20 @@ static bool IsChineseOrJapanese(nsTextFrame* aFrame) #ifdef DEBUG static bool IsInBounds(const gfxSkipCharsIterator& aStart, int32_t aContentLength, - uint32_t aOffset, uint32_t aLength) { - if (aStart.GetSkippedOffset() > aOffset) + gfxTextRun::Range aRange) { + if (aStart.GetSkippedOffset() > aRange.start) return false; if (aContentLength == INT32_MAX) return true; gfxSkipCharsIterator iter(aStart); iter.AdvanceOriginal(aContentLength); - return iter.GetSkippedOffset() >= aOffset + aLength; + return iter.GetSkippedOffset() >= aRange.end; } #endif class MOZ_STACK_CLASS PropertyProvider : public gfxTextRun::PropertyProvider { + typedef gfxTextRun::Range Range; + public: /** * Use this constructor for reflow, when we don't know what text is @@ -3002,10 +3005,9 @@ public: void InitializeForMeasure(); - virtual void GetSpacing(uint32_t aStart, uint32_t aLength, Spacing* aSpacing); + virtual void GetSpacing(Range aRange, Spacing* aSpacing); virtual gfxFloat GetHyphenWidth(); - virtual void GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, - bool* aBreakBefore); + virtual void GetHyphenationBreaks(Range aRange, bool* aBreakBefore); virtual int8_t GetHyphensOption() { return mTextStyle->mHyphens; } @@ -3018,14 +3020,13 @@ public: return mTextRun->GetAppUnitsPerDevUnit(); } - void GetSpacingInternal(uint32_t aStart, uint32_t aLength, Spacing* aSpacing, - bool aIgnoreTabs); + void GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs); /** * Compute the justification information in given DOM range, and fill data * necessary for computation of spacing. */ - void ComputeJustification(int32_t aOffset, int32_t aLength); + void ComputeJustification(Range aRange); const nsStyleText* StyleText() { return mTextStyle; } nsTextFrame* GetFrame() { return mFrame; } @@ -3052,7 +3053,7 @@ public: return mFontMetrics; } - void CalcTabWidths(uint32_t aTransformedStart, uint32_t aTransformedLength); + void CalcTabWidths(Range aTransformedRange); const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; } @@ -3147,16 +3148,16 @@ static void FindClusterEnd(gfxTextRun* aTextRun, int32_t aOriginalEnd, } void -PropertyProvider::ComputeJustification(int32_t aOffset, int32_t aLength) +PropertyProvider::ComputeJustification(Range aRange) { bool isCJ = IsChineseOrJapanese(mFrame); - nsSkipCharsRunIterator - run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength); - run.SetOriginalOffset(aOffset); + nsSkipCharsRunIterator run( + mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aRange.Length()); + run.SetOriginalOffset(aRange.start); mJustificationArrayStart = run.GetSkippedOffset(); MOZ_ASSERT(mJustificationAssignments.IsEmpty()); - mJustificationAssignments.SetCapacity(aLength); + mJustificationAssignments.SetCapacity(aRange.Length()); while (run.NextRun()) { uint32_t originalOffset = run.GetOriginalOffset(); uint32_t skippedOffset = run.GetSkippedOffset(); @@ -3215,10 +3216,9 @@ PropertyProvider::ComputeJustification(int32_t aOffset, int32_t aLength) // aStart, aLength in transformed string offsets void -PropertyProvider::GetSpacing(uint32_t aStart, uint32_t aLength, - Spacing* aSpacing) +PropertyProvider::GetSpacing(Range aRange, Spacing* aSpacing) { - GetSpacingInternal(aStart, aLength, aSpacing, + GetSpacingInternal(aRange, aSpacing, (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TAB) == 0); } @@ -3232,28 +3232,28 @@ CanAddSpacingAfter(gfxTextRun* aTextRun, uint32_t aOffset) } void -PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength, - Spacing* aSpacing, bool aIgnoreTabs) +PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, + bool aIgnoreTabs) { - NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds"); + NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds"); uint32_t index; - for (index = 0; index < aLength; ++index) { + for (index = 0; index < aRange.Length(); ++index) { aSpacing[index].mBefore = 0.0; aSpacing[index].mAfter = 0.0; } // Find our offset into the original+transformed string gfxSkipCharsIterator start(mStart); - start.SetSkippedOffset(aStart); + start.SetSkippedOffset(aRange.start); // First, compute the word and letter spacing if (mWordSpacing || mLetterSpacing) { // Iterate over non-skipped characters - nsSkipCharsRunIterator - run(start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength); + nsSkipCharsRunIterator run( + start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length()); while (run.NextRun()) { - uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart; + uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start; gfxSkipCharsIterator iter = run.GetPos(); for (int32_t i = 0; i < run.GetRunLength(); ++i) { if (CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i)) { @@ -3267,7 +3267,8 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength, iter.SetSkippedOffset(run.GetSkippedOffset() + i); FindClusterEnd(mTextRun, run.GetOriginalOffset() + run.GetRunLength(), &iter); - aSpacing[iter.GetSkippedOffset() - aStart].mAfter += mWordSpacing; + uint32_t runOffset = iter.GetSkippedOffset() - aRange.start; + aSpacing[runOffset].mAfter += mWordSpacing; } } } @@ -3279,10 +3280,11 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength, // Now add tab spacing, if there is any if (!aIgnoreTabs) { - CalcTabWidths(aStart, aLength); + CalcTabWidths(aRange); if (mTabWidths) { mTabWidths->ApplySpacing(aSpacing, - aStart - mStart.GetSkippedOffset(), aLength); + aRange.start - mStart.GetSkippedOffset(), + aRange.Length()); } } @@ -3293,15 +3295,16 @@ PropertyProvider::GetSpacingInternal(uint32_t aStart, uint32_t aLength, // ignore those spaces. auto arrayEnd = mJustificationArrayStart + static_cast(mJustificationAssignments.Length()); - auto end = std::min(aStart + aLength, arrayEnd); - MOZ_ASSERT(aStart >= mJustificationArrayStart); + auto end = std::min(aRange.end, arrayEnd); + MOZ_ASSERT(aRange.start >= mJustificationArrayStart); JustificationApplicationState state( mTotalJustificationGaps, NSToCoordRound(mJustificationSpacing)); - for (auto i = aStart; i < end; i++) { + for (auto i = aRange.start; i < end; i++) { const auto& assign = mJustificationAssignments[i - mJustificationArrayStart]; - aSpacing[i - aStart].mBefore += state.Consume(assign.mGapsAtStart); - aSpacing[i - aStart].mAfter += state.Consume(assign.mGapsAtEnd); + uint32_t offset = i - aRange.start; + aSpacing[offset].mBefore += state.Consume(assign.mGapsAtStart); + aSpacing[offset].mAfter += state.Consume(assign.mGapsAtEnd); } } } @@ -3331,7 +3334,7 @@ AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, } void -PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) +PropertyProvider::CalcTabWidths(Range aRange) { if (!mTabWidths) { if (mReflowing && !mLineContainer) { @@ -3346,7 +3349,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) // If we're not reflowing, we should have already computed the // tab widths; check that they're available as far as the last // tab character present (if any) - for (uint32_t i = aStart + aLength; i > aStart; --i) { + for (uint32_t i = aRange.end; i > aRange.start; --i) { if (mTextRun->CharIsTab(i - 1)) { uint32_t startOffset = mStart.GetSkippedOffset(); NS_ASSERTION(mTabWidths && mTabWidths->mLimit + startOffset >= i, @@ -3360,18 +3363,18 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) } uint32_t startOffset = mStart.GetSkippedOffset(); - MOZ_ASSERT(aStart >= startOffset, "wrong start offset"); - MOZ_ASSERT(aStart + aLength <= startOffset + mLength, "beyond the end"); + MOZ_ASSERT(aRange.start >= startOffset, "wrong start offset"); + MOZ_ASSERT(aRange.end <= startOffset + mLength, "beyond the end"); uint32_t tabsEnd = (mTabWidths ? mTabWidths->mLimit : mTabWidthsAnalyzedLimit) + startOffset; - if (tabsEnd < aStart + aLength) { + if (tabsEnd < aRange.end) { NS_ASSERTION(mReflowing, "We need precomputed tab widths, but don't have enough."); gfxFloat tabWidth = -1; - for (uint32_t i = tabsEnd; i < aStart + aLength; ++i) { + for (uint32_t i = tabsEnd; i < aRange.end; ++i) { Spacing spacing; - GetSpacingInternal(i, 1, &spacing, true); + GetSpacingInternal(Range(i, i + 1), &spacing, true); mOffsetFromBlockOriginForTabs += spacing.mBefore; if (!mTextRun->CharIsTab(i)) { @@ -3382,7 +3385,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) ++clusterEnd; } mOffsetFromBlockOriginForTabs += - mTextRun->GetAdvanceWidth(i, clusterEnd - i, nullptr); + mTextRun->GetAdvanceWidth(Range(i, clusterEnd), nullptr); } } else { if (!mTabWidths) { @@ -3400,7 +3403,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) } if (mTabWidths) { - mTabWidths->mLimit = aStart + aLength - startOffset; + mTabWidths->mLimit = aRange.end - startOffset; } } @@ -3408,7 +3411,7 @@ PropertyProvider::CalcTabWidths(uint32_t aStart, uint32_t aLength) // Delete any stale property that may be left on the frame mFrame->Properties().Delete(TabWidthProperty()); mTabWidthsAnalyzedLimit = std::max(mTabWidthsAnalyzedLimit, - aStart + aLength - startOffset); + aRange.end - startOffset); } } @@ -3422,23 +3425,22 @@ PropertyProvider::GetHyphenWidth() } void -PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, - bool* aBreakBefore) +PropertyProvider::GetHyphenationBreaks(Range aRange, bool* aBreakBefore) { - NS_PRECONDITION(IsInBounds(mStart, mLength, aStart, aLength), "Range out of bounds"); + NS_PRECONDITION(IsInBounds(mStart, mLength, aRange), "Range out of bounds"); NS_PRECONDITION(mLength != INT32_MAX, "Can't call this with undefined length"); if (!mTextStyle->WhiteSpaceCanWrap(mFrame) || mTextStyle->mHyphens == NS_STYLE_HYPHENS_NONE) { - memset(aBreakBefore, false, aLength*sizeof(bool)); + memset(aBreakBefore, false, aRange.Length() * sizeof(bool)); return; } // Iterate through the original-string character runs - nsSkipCharsRunIterator - run(mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength); - run.SetSkippedOffset(aStart); + nsSkipCharsRunIterator run( + mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length()); + run.SetSkippedOffset(aRange.start); // We need to visit skipped characters so that we can detect SHY run.SetVisitSkipped(); @@ -3457,7 +3459,7 @@ PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, allowHyphenBreakBeforeNextChar = mFrag->CharAt(run.GetOriginalOffset() + run.GetRunLength() - 1) == CH_SHY; } else { - int32_t runOffsetInSubstring = run.GetSkippedOffset() - aStart; + int32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start; memset(aBreakBefore + runOffsetInSubstring, false, run.GetRunLength()*sizeof(bool)); // Don't allow hyphen breaks at the start of the line aBreakBefore[runOffsetInSubstring] = allowHyphenBreakBeforeNextChar && @@ -3468,8 +3470,8 @@ PropertyProvider::GetHyphenationBreaks(uint32_t aStart, uint32_t aLength, } if (mTextStyle->mHyphens == NS_STYLE_HYPHENS_AUTO) { - for (uint32_t i = 0; i < aLength; ++i) { - if (mTextRun->CanHyphenateBefore(aStart + i)) { + for (uint32_t i = 0; i < aRange.Length(); ++i) { + if (mTextRun->CanHyphenateBefore(aRange.start + i)) { aBreakBefore[i] = true; } } @@ -3497,12 +3499,6 @@ PropertyProvider::InitializeForMeasure() } -static uint32_t GetSkippedDistance(const gfxSkipCharsIterator& aStart, - const gfxSkipCharsIterator& aEnd) -{ - return aEnd.GetSkippedOffset() - aStart.GetSkippedOffset(); -} - void PropertyProvider::SetupJustificationSpacing(bool aPostReflow) { @@ -3519,8 +3515,8 @@ PropertyProvider::SetupJustificationSpacing(bool aPostReflow) mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow); end.AdvanceOriginal(trimmed.mLength); gfxSkipCharsIterator realEnd(end); - ComputeJustification(start.GetOriginalOffset(), - end.GetOriginalOffset() - start.GetOriginalOffset()); + ComputeJustification(Range(uint32_t(start.GetOriginalOffset()), + uint32_t(end.GetOriginalOffset()))); auto assign = mFrame->GetJustificationAssignment(); mTotalJustificationGaps = @@ -3535,8 +3531,8 @@ PropertyProvider::SetupJustificationSpacing(bool aPostReflow) // so its advance "width" is actually a height in vertical writing modes, // corresponding to the inline-direction of the frame. gfxFloat naturalWidth = - mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(), - GetSkippedDistance(mStart, realEnd), this); + mTextRun->GetAdvanceWidth(Range(mStart.GetSkippedOffset(), + realEnd.GetSkippedOffset()), this); if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) { naturalWidth += GetHyphenWidth(); } @@ -5223,8 +5219,7 @@ nsTextFrame::UpdateTextEmphasis(WritingMode aWM, PropertyProvider& aProvider) EmphasisMarkInfo* info = new EmphasisMarkInfo; info->textRun = GenerateTextRunForEmphasisMarks(this, fm, aWM, styleText); - info->advance = - info->textRun->GetAdvanceWidth(0, info->textRun->GetLength(), nullptr); + info->advance = info->textRun->GetAdvanceWidth(); // Calculate the baseline offset LogicalSide side = styleText->TextEmphasisSide(aWM); @@ -5780,26 +5775,24 @@ public: * for RTL) */ SelectionIterator(SelectionDetails** aSelectionDetails, - int32_t aStart, int32_t aLength, - PropertyProvider& aProvider, gfxTextRun* aTextRun, - gfxFloat aXOffset); + gfxTextRun::Range aRange, PropertyProvider& aProvider, + gfxTextRun* aTextRun, gfxFloat aXOffset); /** * Returns the next segment of uniformly selected (or not) text. * @param aXOffset the offset from the origin of the frame to the start * of the text (the left baseline origin for LTR, the right baseline origin * for RTL) - * @param aOffset the transformed string offset of the text for this segment - * @param aLength the transformed string length of the text for this segment + * @param aRange the transformed string range of the text for this segment * @param aHyphenWidth if a hyphen is to be rendered after the text, the * width of the hyphen, otherwise zero * @param aType the selection type for this segment * @param aStyle the selection style for this segment * @return false if there are no more segments */ - bool GetNextSegment(gfxFloat* aXOffset, uint32_t* aOffset, uint32_t* aLength, - gfxFloat* aHyphenWidth, SelectionType* aType, - TextRangeStyle* aStyle); + bool GetNextSegment(gfxFloat* aXOffset, gfxTextRun::Range* aRange, + gfxFloat* aHyphenWidth, SelectionType* aType, + TextRangeStyle* aStyle); void UpdateWithAdvance(gfxFloat aAdvance) { mXOffset += aAdvance*mTextRun->GetDirection(); } @@ -5809,33 +5802,34 @@ private: PropertyProvider& mProvider; gfxTextRun* mTextRun; gfxSkipCharsIterator mIterator; - int32_t mOriginalStart; - int32_t mOriginalEnd; + gfxTextRun::Range mOriginalRange; gfxFloat mXOffset; }; SelectionIterator::SelectionIterator(SelectionDetails** aSelectionDetails, - int32_t aStart, int32_t aLength, PropertyProvider& aProvider, - gfxTextRun* aTextRun, gfxFloat aXOffset) + gfxTextRun::Range aRange, + PropertyProvider& aProvider, + gfxTextRun* aTextRun, gfxFloat aXOffset) : mSelectionDetails(aSelectionDetails), mProvider(aProvider), mTextRun(aTextRun), mIterator(aProvider.GetStart()), - mOriginalStart(aStart), mOriginalEnd(aStart + aLength), - mXOffset(aXOffset) + mOriginalRange(aRange), mXOffset(aXOffset) { - mIterator.SetOriginalOffset(aStart); + mIterator.SetOriginalOffset(aRange.start); } bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset, - uint32_t* aOffset, uint32_t* aLength, gfxFloat* aHyphenWidth, - SelectionType* aType, TextRangeStyle* aStyle) + gfxTextRun::Range* aRange, + gfxFloat* aHyphenWidth, + SelectionType* aType, + TextRangeStyle* aStyle) { - if (mIterator.GetOriginalOffset() >= mOriginalEnd) + if (mIterator.GetOriginalOffset() >= int32_t(mOriginalRange.end)) return false; // save offset into transformed string now uint32_t runOffset = mIterator.GetSkippedOffset(); - int32_t index = mIterator.GetOriginalOffset() - mOriginalStart; + uint32_t index = mIterator.GetOriginalOffset() - mOriginalRange.start; SelectionDetails* sdptr = mSelectionDetails[index]; SelectionType type = sdptr ? sdptr->mType : nsISelectionController::SELECTION_NONE; @@ -5843,14 +5837,14 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset, if (sdptr) { style = sdptr->mTextRangeStyle; } - for (++index; mOriginalStart + index < mOriginalEnd; ++index) { + for (++index; index < mOriginalRange.Length(); ++index) { if (sdptr != mSelectionDetails[index]) break; } - mIterator.SetOriginalOffset(index + mOriginalStart); + mIterator.SetOriginalOffset(index + mOriginalRange.start); // Advance to the next cluster boundary - while (mIterator.GetOriginalOffset() < mOriginalEnd && + while (mIterator.GetOriginalOffset() < int32_t(mOriginalRange.end) && !mIterator.IsOriginalCharSkipped() && !mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) { mIterator.AdvanceOriginal(1); @@ -5858,11 +5852,12 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset, bool haveHyphenBreak = (mProvider.GetFrame()->GetStateBits() & TEXT_HYPHEN_BREAK) != 0; - *aOffset = runOffset; - *aLength = mIterator.GetSkippedOffset() - runOffset; + aRange->start = runOffset; + aRange->end = mIterator.GetSkippedOffset(); *aXOffset = mXOffset; *aHyphenWidth = 0; - if (mIterator.GetOriginalOffset() == mOriginalEnd && haveHyphenBreak) { + if (mIterator.GetOriginalOffset() == int32_t(mOriginalRange.end) && + haveHyphenBreak) { *aHyphenWidth = mProvider.GetHyphenWidth(); } *aType = type; @@ -5883,8 +5878,7 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun, return; gfxTextRun::Metrics hyphenMetrics = - hyphenTextRun->MeasureText(0, hyphenTextRun->GetLength(), aBoundingBoxType, - aDrawTarget, nullptr); + hyphenTextRun->MeasureText(aBoundingBoxType, aDrawTarget); if (aTextFrame->GetWritingMode().IsLineInverted()) { hyphenMetrics.mBoundingBox.y = -hyphenMetrics.mBoundingBox.YMost(); } @@ -5892,7 +5886,7 @@ AddHyphenToMetrics(nsTextFrame* aTextFrame, gfxTextRun* aBaseTextRun, } void -nsTextFrame::PaintOneShadow(uint32_t aOffset, uint32_t aLength, +nsTextFrame::PaintOneShadow(Range aRange, nsCSSShadowItem* aShadowDetails, PropertyProvider* aProvider, const nsRect& aDirtyRect, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, @@ -5960,14 +5954,19 @@ nsTextFrame::PaintOneShadow(uint32_t aOffset, uint32_t aLength, // Remember that the box blur context has a device offset on it, so we don't need to // translate any coordinates to fit on the surface. gfxFloat advanceWidth; - gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y, - aDirtyRect.width, aDirtyRect.height); - DrawText(shadowContext, dirtyRect, aFramePt + shadowOffset, - aTextBaselinePt + shadowOffset, aOffset, aLength, *aProvider, - nsTextPaintStyle(this), - aCtx == shadowContext ? shadowColor : NS_RGB(0, 0, 0), aClipEdges, - advanceWidth, (GetStateBits() & TEXT_HYPHEN_BREAK) != 0, - decorationOverrideColor); + nsTextPaintStyle textPaintStyle(this); + DrawTextParams params(shadowContext); + params.advanceWidth = &advanceWidth; + params.dirtyRect = gfxRect(aDirtyRect.x, aDirtyRect.y, + aDirtyRect.width, aDirtyRect.height); + params.framePt = aFramePt + shadowOffset; + params.provider = aProvider; + params.textStyle = &textPaintStyle; + params.textColor = aCtx == shadowContext ? shadowColor : NS_RGB(0, 0, 0); + params.clipEdges = &aClipEdges; + params.drawSoftHyphen = (GetStateBits() & TEXT_HYPHEN_BREAK) != 0; + params.decorationOverrideColor = decorationOverrideColor; + DrawText(aRange, aTextBaselinePt + shadowOffset, params); contextBoxBlur.DoPaint(); aCtx->Restore(); @@ -5980,7 +5979,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, PropertyProvider& aProvider, - uint32_t aContentOffset, uint32_t aContentLength, + Range aContentRange, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, SelectionType* aAllTypes, const nsCharClipDisplayItem::ClipEdges& aClipEdges, @@ -5989,22 +5988,22 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, // Figure out which selections control the colors to use for each character. AutoTArray prevailingSelectionsBuffer; SelectionDetails** prevailingSelections = - prevailingSelectionsBuffer.AppendElements(aContentLength, fallible); + prevailingSelectionsBuffer.AppendElements(aContentRange.Length(), fallible); if (!prevailingSelections) { return false; } SelectionType allTypes = 0; - for (uint32_t i = 0; i < aContentLength; ++i) { + for (uint32_t i = 0; i < aContentRange.Length(); ++i) { prevailingSelections[i] = nullptr; } SelectionDetails *sdptr = aDetails; bool anyBackgrounds = false; while (sdptr) { - int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset)); - int32_t end = std::min(int32_t(aContentLength), - sdptr->mEnd - int32_t(aContentOffset)); + int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start)); + int32_t end = std::min(int32_t(aContentRange.Length()), + sdptr->mEnd - int32_t(aContentRange.start)); SelectionType type = sdptr->mType; if (start < end) { allTypes |= type; @@ -6037,23 +6036,23 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, const gfxFloat startIOffset = vertical ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x; gfxFloat iOffset, hyphenWidth; - uint32_t offset, length; // in transformed string + Range range; // in transformed string SelectionType type; TextRangeStyle rangeStyle; // Draw background colors if (anyBackgrounds) { int32_t appUnitsPerDevPixel = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel(); LayoutDeviceRect dirtyRect = AppUnitGfxRectToDevRect(aDirtyRect, appUnitsPerDevPixel); - SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength, + SelectionIterator iterator(prevailingSelections, aContentRange, aProvider, mTextRun, startIOffset); - while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth, + while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth, &type, &rangeStyle)) { nscolor foreground, background; GetSelectionTextColors(type, aTextPaintStyle, rangeStyle, &foreground, &background); // Draw background color gfxFloat advance = hyphenWidth + - mTextRun->GetAdvanceWidth(offset, length, &aProvider); + mTextRun->GetAdvanceWidth(range, &aProvider); if (NS_GET_A(background) > 0) { gfxRect bgRect; gfxFloat offs = iOffset - (mTextRun->IsInlineReversed() ? advance : 0); @@ -6071,14 +6070,24 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, iterator.UpdateWithAdvance(advance); } } + + gfxFloat advance; + DrawTextParams params(aCtx); + params.dirtyRect = aDirtyRect; + params.framePt = aFramePt; + params.provider = &aProvider; + params.textStyle = &aTextPaintStyle; + params.clipEdges = &aClipEdges; + params.advanceWidth = &advance; + params.callbacks = aCallbacks; // Draw text const nsStyleText* textStyle = StyleText(); nsRect dirtyRect(aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height); - SelectionIterator iterator(prevailingSelections, aContentOffset, aContentLength, + SelectionIterator iterator(prevailingSelections, aContentRange, aProvider, mTextRun, startIOffset); - while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth, + while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth, &type, &rangeStyle)) { nscolor foreground, background; GetSelectionTextColors(type, aTextPaintStyle, rangeStyle, @@ -6094,18 +6103,17 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx, if (shadow) { nscoord startEdge = iOffset; if (mTextRun->IsInlineReversed()) { - startEdge -= mTextRun->GetAdvanceWidth(offset, length, &aProvider) + - hyphenWidth; + startEdge -= hyphenWidth + + mTextRun->GetAdvanceWidth(range, &aProvider); } - PaintShadows(shadow, offset, length, dirtyRect, aFramePt, textBaselinePt, + PaintShadows(shadow, range, dirtyRect, aFramePt, textBaselinePt, startEdge, aProvider, foreground, aClipEdges, aCtx); } // Draw text segment - gfxFloat advance; - DrawText(aCtx, aDirtyRect, aFramePt, textBaselinePt, - offset, length, aProvider, aTextPaintStyle, foreground, aClipEdges, - advance, hyphenWidth > 0, nullptr, nullptr, aCallbacks); + params.textColor = foreground; + params.drawSoftHyphen = hyphenWidth > 0; + DrawText(range, textBaselinePt, params); advance += hyphenWidth; iterator.UpdateWithAdvance(advance); } @@ -6116,8 +6124,7 @@ void nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, - PropertyProvider& aProvider, - uint32_t aContentOffset, uint32_t aContentLength, + PropertyProvider& aProvider, Range aContentRange, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, SelectionType aSelectionType, nsTextFrame::DrawPathCallbacks* aCallbacks) @@ -6129,20 +6136,20 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, // Figure out which characters will be decorated for this selection. AutoTArray selectedCharsBuffer; SelectionDetails** selectedChars = - selectedCharsBuffer.AppendElements(aContentLength, fallible); + selectedCharsBuffer.AppendElements(aContentRange.Length(), fallible); if (!selectedChars) { return; } - for (uint32_t i = 0; i < aContentLength; ++i) { + for (uint32_t i = 0; i < aContentRange.Length(); ++i) { selectedChars[i] = nullptr; } SelectionDetails *sdptr = aDetails; while (sdptr) { if (sdptr->mType == aSelectionType) { - int32_t start = std::max(0, sdptr->mStart - int32_t(aContentOffset)); - int32_t end = std::min(int32_t(aContentLength), - sdptr->mEnd - int32_t(aContentOffset)); + int32_t start = std::max(0, sdptr->mStart - int32_t(aContentRange.start)); + int32_t end = std::min(int32_t(aContentRange.Length()), + sdptr->mEnd - int32_t(aContentRange.start)); for (int32_t i = start; i < end; ++i) { selectedChars[i] = sdptr; } @@ -6169,10 +6176,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, gfxFloat startIOffset = verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x; - SelectionIterator iterator(selectedChars, aContentOffset, aContentLength, + SelectionIterator iterator(selectedChars, aContentRange, aProvider, mTextRun, startIOffset); gfxFloat iOffset, hyphenWidth; - uint32_t offset, length; + Range range; int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel(); // XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint? gfxPoint pt; @@ -6186,10 +6193,10 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx, gfxFloat decorationOffsetDir = mTextRun->IsSidewaysLeft() ? -1.0 : 1.0; SelectionType type; TextRangeStyle selectedStyle; - while (iterator.GetNextSegment(&iOffset, &offset, &length, &hyphenWidth, + while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth, &type, &selectedStyle)) { gfxFloat advance = hyphenWidth + - mTextRun->GetAdvanceWidth(offset, length, &aProvider); + mTextRun->GetAdvanceWidth(range, &aProvider); if (type == aSelectionType) { if (verticalRun) { pt.y = (aFramePt.y + iOffset - @@ -6215,7 +6222,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, PropertyProvider& aProvider, - uint32_t aContentOffset, uint32_t aContentLength, + Range aContentRange, nsTextPaintStyle& aTextPaintStyle, const nsCharClipDisplayItem::ClipEdges& aClipEdges, gfxTextContextPaint* aContextPaint, @@ -6230,7 +6237,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, SelectionType allTypes; if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect, - aProvider, aContentOffset, aContentLength, + aProvider, aContentRange, aTextPaintStyle, details, &allTypes, aClipEdges, aCallbacks)) { DestroySelectionDetails(details); @@ -6249,9 +6256,8 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, // (there might not be any for this type but that's OK, // PaintTextSelectionDecorations will exit early). PaintTextSelectionDecorations(aCtx, aFramePt, aTextBaselinePt, aDirtyRect, - aProvider, aContentOffset, aContentLength, - aTextPaintStyle, details, type, - aCallbacks); + aProvider, aContentRange, aTextPaintStyle, + details, type, aCallbacks); } } @@ -6262,9 +6268,9 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx, void nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM, const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, + Range aRange, const nscolor* aDecorationOverrideColor, - PropertyProvider& aProvider) + PropertyProvider* aProvider) { const auto info = Properties().Get(EmphasisMarkProperty()); if (!info) { @@ -6285,7 +6291,7 @@ nsTextFrame::DrawEmphasisMarks(gfxContext* aContext, WritingMode aWM, } } mTextRun->DrawEmphasisMarks(aContext, info->textRun, info->advance, - pt, aOffset, aLength, &aProvider); + pt, aRange, aProvider); } nscolor @@ -6345,13 +6351,13 @@ nsTextFrame::GetCaretColorAt(int32_t aOffset) return result; } -static uint32_t -ComputeTransformedLength(PropertyProvider& aProvider) +static gfxTextRun::Range +ComputeTransformedRange(PropertyProvider& aProvider) { gfxSkipCharsIterator iter(aProvider.GetStart()); uint32_t start = iter.GetSkippedOffset(); iter.AdvanceOriginal(aProvider.GetOriginalLength()); - return iter.GetSkippedOffset() - start; + return gfxTextRun::Range(start, iter.GetSkippedOffset()); } bool @@ -6371,8 +6377,9 @@ nsTextFrame::MeasureCharClippedText(nscoord aVisIStartEdge, // Trim trailing whitespace provider.InitializeForDisplay(true); - uint32_t startOffset = provider.GetStart().GetSkippedOffset(); - uint32_t maxLength = ComputeTransformedLength(provider); + Range range = ComputeTransformedRange(provider); + uint32_t startOffset = range.start; + uint32_t maxLength = range.Length(); return MeasureCharClippedText(provider, aVisIStartEdge, aVisIEndEdge, &startOffset, &maxLength, aSnappedStartEdge, aSnappedEndEdge); @@ -6422,8 +6429,8 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider, while (maxLength > 0) { uint32_t clusterLength = GetClusterLength(mTextRun, offset, maxLength, rtl); - advanceWidth += - mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider); + advanceWidth += mTextRun-> + GetAdvanceWidth(Range(offset, offset + clusterLength), &aProvider); maxLength -= clusterLength; offset += clusterLength; if (advanceWidth >= maxAdvance) { @@ -6441,8 +6448,8 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider, while (maxLength > 0) { uint32_t clusterLength = GetClusterLength(mTextRun, offset, maxLength, rtl); - gfxFloat nextAdvance = advanceWidth + - mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider); + gfxFloat nextAdvance = advanceWidth + mTextRun->GetAdvanceWidth( + Range(offset, offset + clusterLength), &aProvider); if (nextAdvance > maxAdvance) { break; } @@ -6461,7 +6468,7 @@ nsTextFrame::MeasureCharClippedText(PropertyProvider& aProvider, void nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow, - uint32_t aOffset, uint32_t aLength, + Range aRange, const nsRect& aDirtyRect, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, @@ -6476,7 +6483,7 @@ nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow, } gfxTextRun::Metrics shadowMetrics = - mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS, + mTextRun->MeasureText(aRange, gfxFont::LOOSE_INK_EXTENTS, nullptr, &aProvider); if (GetWritingMode().IsLineInverted()) { Swap(shadowMetrics.mAscent, shadowMetrics.mDescent); @@ -6511,8 +6518,7 @@ nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow, } for (uint32_t i = aShadow->Length(); i > 0; --i) { - PaintOneShadow(aOffset, aLength, - aShadow->ShadowAt(i - 1), &aProvider, + PaintOneShadow(aRange, aShadow->ShadowAt(i - 1), &aProvider, aDirtyRect, aFramePt, aTextBaselinePt, aCtx, aForegroundColor, aClipEdges, aLeftEdgeOffset, @@ -6566,8 +6572,9 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, gfxPoint(reversed ? gfxFloat(aPt.x + frameWidth) : framePt.x, nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent)); } - uint32_t startOffset = provider.GetStart().GetSkippedOffset(); - uint32_t maxLength = ComputeTransformedLength(provider); + Range range = ComputeTransformedRange(provider); + uint32_t startOffset = range.start; + uint32_t maxLength = range.Length(); nscoord snappedStartEdge, snappedEndEdge; if (!MeasureCharClippedText(provider, aItem.mVisIStartEdge, aItem.mVisIEndEdge, &startOffset, &maxLength, &snappedStartEdge, &snappedEndEdge)) { @@ -6589,13 +6596,12 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, if (aItem.mIsFrameSelected.value()) { MOZ_ASSERT(aOpacity == 1.0f, "We don't support opacity with selections!"); gfxSkipCharsIterator tmp(provider.GetStart()); - int32_t contentOffset = tmp.ConvertSkippedToOriginal(startOffset); - int32_t contentLength = - tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset; + Range contentRange( + uint32_t(tmp.ConvertSkippedToOriginal(startOffset)), + uint32_t(tmp.ConvertSkippedToOriginal(startOffset + maxLength))); if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect, - provider, contentOffset, contentLength, - textPaintStyle, clipEdges, aContextPaint, - aCallbacks)) { + provider, contentRange, textPaintStyle, + clipEdges, aContextPaint, aCallbacks)) { return; } } @@ -6607,99 +6613,93 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt, foregroundColor = gfxColor.ToABGR(); } + range = Range(startOffset, startOffset + maxLength); if (!aCallbacks) { const nsStyleText* textStyle = StyleText(); - PaintShadows(textStyle->mTextShadow, startOffset, maxLength, - aDirtyRect, framePt, textBaselinePt, snappedStartEdge, provider, - foregroundColor, clipEdges, ctx); + PaintShadows( + textStyle->mTextShadow, range, aDirtyRect, framePt, textBaselinePt, + snappedStartEdge, provider, foregroundColor, clipEdges, ctx); } gfxFloat advanceWidth; - DrawText(ctx, dirtyRect, framePt, textBaselinePt, startOffset, maxLength, provider, - textPaintStyle, foregroundColor, clipEdges, advanceWidth, - (GetStateBits() & TEXT_HYPHEN_BREAK) != 0, - nullptr, aContextPaint, aCallbacks); + DrawTextParams params(ctx); + params.dirtyRect = dirtyRect; + params.framePt = framePt; + params.provider = &provider; + params.advanceWidth = &advanceWidth; + params.textStyle = &textPaintStyle; + params.textColor = foregroundColor; + params.clipEdges = &clipEdges; + params.drawSoftHyphen = (GetStateBits() & TEXT_HYPHEN_BREAK) != 0; + params.contextPaint = aContextPaint; + params.callbacks = aCallbacks; + DrawText(range, textBaselinePt, params); } static void DrawTextRun(gfxTextRun* aTextRun, - gfxContext* const aCtx, const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, - PropertyProvider* aProvider, - nscolor aTextColor, - gfxFloat* aAdvanceWidth, - gfxTextContextPaint* aContextPaint, - nsTextFrame::DrawPathCallbacks* aCallbacks) + gfxTextRun::Range aRange, + const nsTextFrame::DrawTextRunParams& aParams) { - DrawMode drawMode = aCallbacks ? DrawMode::GLYPH_PATH : - DrawMode::GLYPH_FILL; - if (aCallbacks) { - aCallbacks->NotifyBeforeText(aTextColor); - aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength, - aProvider, aAdvanceWidth, aContextPaint, aCallbacks); - aCallbacks->NotifyAfterText(); + gfxTextRun::DrawParams params(aParams.context); + params.drawMode = aParams.callbacks ? DrawMode::GLYPH_PATH + : DrawMode::GLYPH_FILL; + params.provider = aParams.provider; + params.advanceWidth = aParams.advanceWidth; + params.contextPaint = aParams.contextPaint; + params.callbacks = aParams.callbacks; + if (aParams.callbacks) { + aParams.callbacks->NotifyBeforeText(aParams.textColor); + aTextRun->Draw(aRange, aTextBaselinePt, params); + aParams.callbacks->NotifyAfterText(); } else { - aCtx->SetColor(Color::FromABGR(aTextColor)); - aTextRun->Draw(aCtx, aTextBaselinePt, drawMode, aOffset, aLength, - aProvider, aAdvanceWidth, aContextPaint); + aParams.context->SetColor(Color::FromABGR(aParams.textColor)); + aTextRun->Draw(aRange, aTextBaselinePt, params); } } void -nsTextFrame::DrawTextRun(gfxContext* const aCtx, - const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, - PropertyProvider& aProvider, - nscolor aTextColor, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - gfxTextContextPaint* aContextPaint, - nsTextFrame::DrawPathCallbacks* aCallbacks) +nsTextFrame::DrawTextRun(Range aRange, const gfxPoint& aTextBaselinePt, + const DrawTextRunParams& aParams) { - ::DrawTextRun(mTextRun, aCtx, aTextBaselinePt, aOffset, aLength, &aProvider, - aTextColor, &aAdvanceWidth, aContextPaint, aCallbacks); + MOZ_ASSERT(aParams.advanceWidth, "Must provide advanceWidth"); + ::DrawTextRun(mTextRun, aTextBaselinePt, aRange, aParams); - if (aDrawSoftHyphen) { + if (aParams.drawSoftHyphen) { // Don't use ctx as the context, because we need a reference context here, // ctx may be transformed. nsAutoPtr hyphenTextRun(GetHyphenTextRun(mTextRun, nullptr, this)); if (hyphenTextRun.get()) { // For right-to-left text runs, the soft-hyphen is positioned at the left // of the text, minus its own width - gfxFloat hyphenBaselineX = aTextBaselinePt.x + mTextRun->GetDirection() * aAdvanceWidth - - (mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth(0, hyphenTextRun->GetLength(), nullptr) : 0); - ::DrawTextRun(hyphenTextRun.get(), aCtx, + gfxFloat hyphenBaselineX = aTextBaselinePt.x + + mTextRun->GetDirection() * (*aParams.advanceWidth) - + (mTextRun->IsRightToLeft() ? hyphenTextRun->GetAdvanceWidth() : 0); + DrawTextRunParams params = aParams; + params.provider = nullptr; + params.advanceWidth = nullptr; + ::DrawTextRun(hyphenTextRun.get(), gfxPoint(hyphenBaselineX, aTextBaselinePt.y), - 0, hyphenTextRun->GetLength(), - nullptr, aTextColor, nullptr, aContextPaint, aCallbacks); + Range(hyphenTextRun.get()), params); } } } void -nsTextFrame::DrawTextRunAndDecorations( - gfxContext* const aCtx, const gfxRect& aDirtyRect, - const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, - PropertyProvider& aProvider, - const nsTextPaintStyle& aTextStyle, - nscolor aTextColor, - const nsCharClipDisplayItem::ClipEdges& aClipEdges, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - const TextDecorations& aDecorations, - const nscolor* const aDecorationOverrideColor, - gfxTextContextPaint* aContextPaint, - nsTextFrame::DrawPathCallbacks* aCallbacks) +nsTextFrame::DrawTextRunAndDecorations(Range aRange, + const gfxPoint& aTextBaselinePt, + const DrawTextParams& aParams, + const TextDecorations& aDecorations) { - const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel(); + const gfxFloat app = + aParams.textStyle->PresContext()->AppUnitsPerDevPixel(); bool verticalRun = mTextRun->IsVertical(); bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline(); // XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint? - nscoord x = NSToCoordRound(aFramePt.x); - nscoord y = NSToCoordRound(aFramePt.y); + nscoord x = NSToCoordRound(aParams.framePt.x); + nscoord y = NSToCoordRound(aParams.framePt.y); // 'measure' here is textrun-relative, so for a horizontal run it's the // width, while for a vertical run it's the height of the decoration @@ -6707,9 +6707,9 @@ nsTextFrame::DrawTextRunAndDecorations( nscoord measure = verticalRun ? frameSize.height : frameSize.width; if (verticalRun) { - aClipEdges.Intersect(&y, &measure); + aParams.clipEdges->Intersect(&y, &measure); } else { - aClipEdges.Intersect(&x, &measure); + aParams.clipEdges->Intersect(&x, &measure); } // decPt is the physical point where the decoration is to be drawn, @@ -6723,7 +6723,7 @@ nsTextFrame::DrawTextRunAndDecorations( gfxFloat ascent = gfxFloat(mAscent) / app; // The starting edge of the frame in block direction - gfxFloat frameBStart = verticalRun ? aFramePt.x : aFramePt.y; + gfxFloat frameBStart = verticalRun ? aParams.framePt.x : aParams.framePt.y; // In vertical-rl mode, block coordinates are measured from the right, // so we need to adjust here. @@ -6733,8 +6733,10 @@ nsTextFrame::DrawTextRunAndDecorations( ascent = -ascent; } - gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app, - aDirtyRect.Width() / app, aDirtyRect.Height() / app); + gfxRect dirtyRect(aParams.dirtyRect.x / app, + aParams.dirtyRect.y / app, + aParams.dirtyRect.Width() / app, + aParams.dirtyRect.Height() / app); nscoord inflationMinFontSize = nsLayoutUtils::InflationMinFontSizeFor(this); @@ -6759,11 +6761,11 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(aCtx, dirtyRect, dec.mColor, - aDecorationOverrideColor, decPt, 0.0, decSize, ascent, + PaintDecorationLine(aParams.context, dirtyRect, dec.mColor, + aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent, decorationOffsetDir * metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, - dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); + dec.mStyle, eNormalDecoration, aParams.callbacks, verticalRun); } // Overlines for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) { @@ -6781,21 +6783,20 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.underlineSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(aCtx, dirtyRect, dec.mColor, - aDecorationOverrideColor, decPt, 0.0, decSize, ascent, + PaintDecorationLine(aParams.context, dirtyRect, dec.mColor, + aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent, decorationOffsetDir * metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle, - eNormalDecoration, aCallbacks, verticalRun); + eNormalDecoration, aParams.callbacks, verticalRun); } // CSS 2.1 mandates that text be painted after over/underlines, and *then* // line-throughs - DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, aTextColor, - aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks); + DrawTextRun(aRange, aTextBaselinePt, aParams); // Emphasis marks - DrawEmphasisMarks(aCtx, wm, aTextBaselinePt, aOffset, aLength, - aDecorationOverrideColor, aProvider); + DrawEmphasisMarks(aParams.context, wm, aTextBaselinePt, aRange, + aParams.decorationOverrideColor, aParams.provider); // Line-throughs for (uint32_t i = aDecorations.mStrikes.Length(); i-- > 0; ) { @@ -6813,46 +6814,31 @@ nsTextFrame::DrawTextRunAndDecorations( decSize.height = metrics.strikeoutSize; bCoord = (frameBStart - dec.mBaselineOffset) / app; - PaintDecorationLine(aCtx, dirtyRect, dec.mColor, - aDecorationOverrideColor, decPt, 0.0, decSize, ascent, + PaintDecorationLine(aParams.context, dirtyRect, dec.mColor, + aParams.decorationOverrideColor, decPt, 0.0, decSize, ascent, decorationOffsetDir * metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, - dec.mStyle, eNormalDecoration, aCallbacks, verticalRun); + dec.mStyle, eNormalDecoration, aParams.callbacks, verticalRun); } } void -nsTextFrame::DrawText( - gfxContext* const aCtx, const gfxRect& aDirtyRect, - const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, - PropertyProvider& aProvider, - const nsTextPaintStyle& aTextStyle, - nscolor aTextColor, - const nsCharClipDisplayItem::ClipEdges& aClipEdges, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - const nscolor* const aDecorationOverrideColor, - gfxTextContextPaint* aContextPaint, - nsTextFrame::DrawPathCallbacks* aCallbacks) +nsTextFrame::DrawText(Range aRange, const gfxPoint& aTextBaselinePt, + const DrawTextParams& aParams) { TextDecorations decorations; - GetTextDecorations(aTextStyle.PresContext(), - aCallbacks ? eUnresolvedColors : eResolvedColors, + GetTextDecorations(aParams.textStyle->PresContext(), + aParams.callbacks ? eUnresolvedColors : eResolvedColors, decorations); // Hide text decorations if we're currently hiding @font-face fallback text - const bool drawDecorations = !aProvider.GetFontGroup()->ShouldSkipDrawing() && - (decorations.HasDecorationLines() || - StyleText()->HasTextEmphasis()); + const bool drawDecorations = + !aParams.provider->GetFontGroup()->ShouldSkipDrawing() && + (decorations.HasDecorationLines() || StyleText()->HasTextEmphasis()); if (drawDecorations) { - DrawTextRunAndDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt, aOffset, aLength, - aProvider, aTextStyle, aTextColor, aClipEdges, aAdvanceWidth, - aDrawSoftHyphen, decorations, - aDecorationOverrideColor, aContextPaint, aCallbacks); + DrawTextRunAndDecorations(aRange, aTextBaselinePt, aParams, decorations); } else { - DrawTextRun(aCtx, aTextBaselinePt, aOffset, aLength, aProvider, - aTextColor, aAdvanceWidth, aDrawSoftHyphen, aContextPaint, aCallbacks); + DrawTextRun(aRange, aTextBaselinePt, aParams); } } @@ -6905,16 +6891,16 @@ nsTextFrame::IsVisibleInSelection(nsISelection* aSelection) * the length of the prefix. Also returns the width of the prefix in aFitWidth. */ static uint32_t -CountCharsFit(gfxTextRun* aTextRun, uint32_t aStart, uint32_t aLength, +CountCharsFit(gfxTextRun* aTextRun, gfxTextRun::Range aRange, gfxFloat aWidth, PropertyProvider* aProvider, gfxFloat* aFitWidth) { uint32_t last = 0; gfxFloat width = 0; - for (uint32_t i = 1; i <= aLength; ++i) { - if (i == aLength || aTextRun->IsClusterStart(aStart + i)) { - gfxFloat nextWidth = width + - aTextRun->GetAdvanceWidth(aStart + last, i - last, aProvider); + for (uint32_t i = 1; i <= aRange.Length(); ++i) { + if (i == aRange.Length() || aTextRun->IsClusterStart(aRange.start + i)) { + gfxTextRun::Range range(aRange.start + last, aRange.start + i); + gfxFloat nextWidth = width + aTextRun->GetAdvanceWidth(range, aProvider); if (nextWidth > aWidth) break; last = i; @@ -6954,13 +6940,13 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint, ? (mTextRun->IsInlineReversed() ? mRect.height - aPoint.y : aPoint.y) : (mTextRun->IsInlineReversed() ? mRect.width - aPoint.x : aPoint.x); gfxFloat fitWidth; - uint32_t skippedLength = ComputeTransformedLength(provider); + Range skippedRange = ComputeTransformedRange(provider); - uint32_t charsFit = CountCharsFit(mTextRun, - provider.GetStart().GetSkippedOffset(), skippedLength, width, &provider, &fitWidth); + uint32_t charsFit = CountCharsFit(mTextRun, skippedRange, + width, &provider, &fitWidth); int32_t selectedOffset; - if (charsFit < skippedLength) { + if (charsFit < skippedRange.Length()) { // charsFit characters fitted, but no more could fit. See if we're // more than halfway through the cluster.. If we are, choose the next // cluster. @@ -6984,8 +6970,9 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint, // CountCharsFit() left us in the middle of the flag; back up over the // first character of the ligature, and adjust fitWidth accordingly. extraCluster.AdvanceSkipped(-2); // it's a surrogate pair: 2 code units - fitWidth -= mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(), - 2, &provider); + fitWidth -= mTextRun->GetAdvanceWidth( + Range(extraCluster.GetSkippedOffset(), + extraCluster.GetSkippedOffset() + 2), &provider); } } @@ -6994,10 +6981,10 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(nsPoint aPoint, provider.GetStart().GetOriginalOffset() + provider.GetOriginalLength(), &extraClusterLastChar, allowSplitLigature); PropertyProvider::Spacing spacing; + Range extraClusterRange(extraCluster.GetSkippedOffset(), + extraClusterLastChar.GetSkippedOffset() + 1); gfxFloat charWidth = - mTextRun->GetAdvanceWidth(extraCluster.GetSkippedOffset(), - GetSkippedDistance(extraCluster, extraClusterLastChar) + 1, - &provider, &spacing); + mTextRun->GetAdvanceWidth(extraClusterRange, &provider, &spacing); charWidth -= spacing.mBefore + spacing.mAfter; selectedOffset = !aForInsertionPoint || width <= fitWidth + spacing.mBefore + charWidth/2 @@ -7195,10 +7182,9 @@ nsTextFrame::GetPointFromOffset(int32_t inOffset, FindClusterStart(mTextRun, trimmedOffset, &iter); } - gfxFloat advance = - mTextRun->GetAdvanceWidth(properties.GetStart().GetSkippedOffset(), - GetSkippedDistance(properties.GetStart(), iter), - &properties); + Range range(properties.GetStart().GetSkippedOffset(), + iter.GetSkippedOffset()); + gfxFloat advance = mTextRun->GetAdvanceWidth(range, &properties); nscoord iSize = NSToCoordCeilClamped(advance); if (mTextRun->IsVertical()) { @@ -7900,7 +7886,7 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, hyphBreakBefore = hyphBuffer.AppendElements(flowEndInTextRun - start, fallible); if (hyphBreakBefore) { - provider.GetHyphenationBreaks(start, flowEndInTextRun - start, + provider.GetHyphenationBreaks(Range(start, flowEndInTextRun), hyphBreakBefore); } } @@ -7925,9 +7911,8 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, } if (i > wordStart) { - nscoord width = - NSToCoordCeilClamped(textRun->GetAdvanceWidth(wordStart, i - wordStart, - &provider)); + nscoord width = NSToCoordCeilClamped( + textRun->GetAdvanceWidth(Range(wordStart, i), &provider)); width = std::max(0, width); aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width); aData->atStartOfLine = false; @@ -7940,10 +7925,8 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, aData->trailingWhitespace += width; } else { // Some non-whitespace so the old trailingWhitespace is no longer trailing - nscoord wsWidth = - NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart, - i - trimStart, - &provider)); + nscoord wsWidth = NSToCoordCeilClamped( + textRun->GetAdvanceWidth(Range(trimStart, i), &provider)); aData->trailingWhitespace = std::max(0, wsWidth); } } else { @@ -7953,7 +7936,7 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, if (preformattedTab) { PropertyProvider::Spacing spacing; - provider.GetSpacing(i, 1, &spacing); + provider.GetSpacing(Range(i, i + 1), &spacing); aData->currentLine += nscoord(spacing.mBefore); gfxFloat afterTab = AdvanceToNextTab(aData->currentLine, this, @@ -8081,9 +8064,8 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, } if (i > lineStart) { - nscoord width = - NSToCoordCeilClamped(textRun->GetAdvanceWidth(lineStart, i - lineStart, - &provider)); + nscoord width = NSToCoordCeilClamped( + textRun->GetAdvanceWidth(Range(lineStart, i), &provider)); width = std::max(0, width); aData->currentLine = NSCoordSaturatingAdd(aData->currentLine, width); @@ -8095,10 +8077,8 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, aData->trailingWhitespace += width; } else { // Some non-whitespace so the old trailingWhitespace is no longer trailing - nscoord wsWidth = - NSToCoordCeilClamped(textRun->GetAdvanceWidth(trimStart, - i - trimStart, - &provider)); + nscoord wsWidth = NSToCoordCeilClamped( + textRun->GetAdvanceWidth(Range(trimStart, i), &provider)); aData->trailingWhitespace = std::max(0, wsWidth); } } else { @@ -8108,7 +8088,7 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, if (preformattedTab) { PropertyProvider::Spacing spacing; - provider.GetSpacing(i, 1, &spacing); + provider.GetSpacing(Range(i, i + 1), &spacing); aData->currentLine += nscoord(spacing.mBefore); gfxFloat afterTab = AdvanceToNextTab(aData->currentLine, this, @@ -8216,8 +8196,7 @@ nsTextFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const provider.InitializeForDisplay(true); gfxTextRun::Metrics metrics = - mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(), - ComputeTransformedLength(provider), + mTextRun->MeasureText(ComputeTransformedRange(provider), gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aDrawTarget, &provider); if (GetWritingMode().IsLineInverted()) { @@ -8250,8 +8229,7 @@ nsTextFrame::GetPrefWidthTightBounds(nsRenderingContext* aContext, provider.InitializeForMeasure(); gfxTextRun::Metrics metrics = - mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(), - ComputeTransformedLength(provider), + mTextRun->MeasureText(ComputeTransformedRange(provider), gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aContext->GetDrawTarget(), &provider); // Round it like nsTextFrame::ComputeTightBounds() to ensure consistency. @@ -9078,7 +9056,8 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, shouldSuppressLineBreak) && !lineContainer->IsSVGText()) { AddStateBits(TEXT_JUSTIFICATION_ENABLED); - provider.ComputeJustification(offset, charsFit); + provider.ComputeJustification(Range(uint32_t(offset), + uint32_t(offset + charsFit))); aLineLayout.SetJustificationInfo(provider.GetJustificationInfo()); } @@ -9136,13 +9115,14 @@ nsTextFrame::TrimTrailingWhiteSpace(DrawTarget* aDrawTarget) // OK to pass null for the line container. PropertyProvider provider(mTextRun, textStyle, frag, this, start, contentLength, nullptr, 0, nsTextFrame::eInflated); - delta = mTextRun->GetAdvanceWidth(trimmedEnd, endOffset - trimmedEnd, &provider); + delta = mTextRun-> + GetAdvanceWidth(Range(trimmedEnd, endOffset), &provider); result.mChanged = true; } } gfxFloat advanceDelta; - mTextRun->SetLineBreaks(trimmedStart, trimmedEnd - trimmedStart, + mTextRun->SetLineBreaks(Range(trimmedStart, trimmedEnd), (GetStateBits() & TEXT_START_OF_LINE) != 0, true, &advanceDelta); if (advanceDelta != 0) { @@ -9192,8 +9172,7 @@ nsTextFrame::RecomputeOverflow(nsIFrame* aBlockFrame) provider.InitializeForDisplay(false); gfxTextRun::Metrics textMetrics = - mTextRun->MeasureText(provider.GetStart().GetSkippedOffset(), - ComputeTransformedLength(provider), + mTextRun->MeasureText(ComputeTransformedRange(provider), gfxFont::LOOSE_INK_EXTENTS, nullptr, &provider); if (GetWritingMode().IsLineInverted()) { diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index daad2584dd..bfe55ceefa 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -44,6 +44,8 @@ class nsTextFrame : public nsTextFrameBase { typedef mozilla::TextRangeStyle TextRangeStyle; typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::Rect Rect; + typedef mozilla::gfx::Size Size; + typedef gfxTextRun::Range Range; public: NS_DECL_QUERYFRAME_TARGET(nsTextFrame) @@ -403,6 +405,30 @@ public: virtual void NotifySelectionDecorationLinePathEmitted() { } }; + struct DrawTextRunParams + { + gfxContext* context; + PropertyProvider* provider = nullptr; + gfxFloat* advanceWidth = nullptr; + gfxTextContextPaint* contextPaint = nullptr; + DrawPathCallbacks* callbacks = nullptr; + nscolor textColor = NS_RGBA(0, 0, 0, 0); + bool drawSoftHyphen = false; + explicit DrawTextRunParams(gfxContext* aContext) + : context(aContext) {} + }; + + struct DrawTextParams : DrawTextRunParams + { + gfxPoint framePt; + gfxRect dirtyRect; + const nsTextPaintStyle* textStyle = nullptr; + const nsCharClipDisplayItem::ClipEdges* clipEdges = nullptr; + const nscolor* decorationOverrideColor = nullptr; + explicit DrawTextParams(gfxContext* aContext) + : DrawTextRunParams(aContext) {} + }; + // Primary frame paint method called from nsDisplayText. Can also be used // to generate paths rather than paint the frame's text by passing a callback // object. The private DrawText() is what applies the text to a graphics @@ -420,8 +446,7 @@ public: const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, PropertyProvider& aProvider, - uint32_t aContentOffset, - uint32_t aContentLength, + Range aRange, nsTextPaintStyle& aTextPaintStyle, const nsCharClipDisplayItem::ClipEdges& aClipEdges, gfxTextContextPaint* aContextPaint, @@ -436,8 +461,7 @@ public: const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, PropertyProvider& aProvider, - uint32_t aContentOffset, - uint32_t aContentLength, + Range aContentRange, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, SelectionType* aAllTypes, @@ -449,8 +473,7 @@ public: const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect, PropertyProvider& aProvider, - uint32_t aContentOffset, - uint32_t aContentLength, + Range aContentRange, nsTextPaintStyle& aTextPaintStyle, SelectionDetails* aDetails, SelectionType aSelectionType, @@ -459,9 +482,9 @@ public: void DrawEmphasisMarks(gfxContext* aContext, mozilla::WritingMode aWM, const gfxPoint& aTextBaselinePt, - uint32_t aOffset, uint32_t aLength, + Range aRange, const nscolor* aDecorationOverrideColor, - PropertyProvider& aProvider); + PropertyProvider* aProvider); virtual nscolor GetCaretColorAt(int32_t aOffset) override; @@ -612,8 +635,7 @@ protected: nsRect UpdateTextEmphasis(mozilla::WritingMode aWM, PropertyProvider& aProvider); - void PaintOneShadow(uint32_t aOffset, - uint32_t aLength, + void PaintOneShadow(Range aRange, nsCSSShadowItem* aShadowDetails, PropertyProvider* aProvider, const nsRect& aDirtyRect, @@ -627,7 +649,7 @@ protected: uint32_t aBlurFlags); void PaintShadows(nsCSSShadowArray* aShadow, - uint32_t aOffset, uint32_t aLength, + Range aRange, const nsRect& aDirtyRect, const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt, @@ -711,49 +733,15 @@ protected: TextDecorationColorResolution aColorResolution, TextDecorations& aDecorations); - void DrawTextRun(gfxContext* const aCtx, - const gfxPoint& aTextBaselinePt, - uint32_t aOffset, - uint32_t aLength, - PropertyProvider& aProvider, - nscolor aTextColor, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - gfxTextContextPaint* aContextPaint, - DrawPathCallbacks* aCallbacks); + void DrawTextRun(Range aRange, const gfxPoint& aTextBaselinePt, + const DrawTextRunParams& aParams); - void DrawTextRunAndDecorations(gfxContext* const aCtx, - const gfxRect& aDirtyRect, - const gfxPoint& aFramePt, - const gfxPoint& aTextBaselinePt, - uint32_t aOffset, - uint32_t aLength, - PropertyProvider& aProvider, - const nsTextPaintStyle& aTextStyle, - nscolor aTextColor, - const nsCharClipDisplayItem::ClipEdges& aClipEdges, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - const TextDecorations& aDecorations, - const nscolor* const aDecorationOverrideColor, - gfxTextContextPaint* aContextPaint, - DrawPathCallbacks* aCallbacks); + void DrawTextRunAndDecorations(Range aRange, const gfxPoint& aTextBaselinePt, + const DrawTextParams& aParams, + const TextDecorations& aDecorations); - void DrawText(gfxContext* const aCtx, - const gfxRect& aDirtyRect, - const gfxPoint& aFramePt, - const gfxPoint& aTextBaselinePt, - uint32_t aOffset, - uint32_t aLength, - PropertyProvider& aProvider, - const nsTextPaintStyle& aTextStyle, - nscolor aTextColor, - const nsCharClipDisplayItem::ClipEdges& aClipEdges, - gfxFloat& aAdvanceWidth, - bool aDrawSoftHyphen, - const nscolor* const aDecorationOverrideColor = nullptr, - gfxTextContextPaint* aContextPaint = nullptr, - DrawPathCallbacks* aCallbacks = nullptr); + void DrawText(Range aRange, const gfxPoint& aTextBaselinePt, + const DrawTextParams& aParams); // Set non empty rect to aRect, it should be overflow rect or frame rect. // If the result rect is larger than the given rect, this returns true. diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp index d5b702ddce..0b2cab9e1b 100644 --- a/layout/generic/nsTextRunTransformations.cpp +++ b/layout/generic/nsTextRunTransformations.cpp @@ -69,11 +69,11 @@ nsTransformedTextRun::SetCapitalization(uint32_t aStart, uint32_t aLength, } bool -nsTransformedTextRun::SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, +nsTransformedTextRun::SetPotentialLineBreaks(Range aRange, uint8_t* aBreakBefore) { bool changed = - gfxTextRun::SetPotentialLineBreaks(aStart, aLength, aBreakBefore); + gfxTextRun::SetPotentialLineBreaks(aRange, aBreakBefore); if (changed) { mNeedsRebuild = true; } @@ -131,7 +131,7 @@ MergeCharactersInTextRun(gfxTextRun* aDest, gfxTextRun* aSrc, { aDest->ResetGlyphRuns(); - gfxTextRun::GlyphRunIterator iter(aSrc, 0, aSrc->GetLength()); + gfxTextRun::GlyphRunIterator iter(aSrc, gfxTextRun::Range(aSrc)); uint32_t offset = 0; AutoTArray glyphs; while (iter.NextRun()) { @@ -658,8 +658,8 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, // (and also child will be shaped appropriately) NS_ASSERTION(convertedString.Length() == canBreakBeforeArray.Length(), "Dropped characters or break-before values somewhere!"); - child->SetPotentialLineBreaks(0, canBreakBeforeArray.Length(), - canBreakBeforeArray.Elements()); + gfxTextRun::Range range(0, uint32_t(canBreakBeforeArray.Length())); + child->SetPotentialLineBreaks(range, canBreakBeforeArray.Elements()); if (transformedChild) { transformedChild->FinishSettingProperties(aRefDrawTarget, aMFR); } @@ -678,6 +678,6 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun, // We can't steal the data because the child may be cached and stealing // the data would break the cache. aTextRun->ResetGlyphRuns(); - aTextRun->CopyGlyphDataFrom(child, 0, child->GetLength(), 0); + aTextRun->CopyGlyphDataFrom(child, gfxTextRun::Range(child), 0); } } diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h index d1040ede7c..9fc797935e 100644 --- a/layout/generic/nsTextRunTransformations.h +++ b/layout/generic/nsTextRunTransformations.h @@ -130,8 +130,7 @@ public: void SetCapitalization(uint32_t aStart, uint32_t aLength, bool* aCapitalization); - virtual bool SetPotentialLineBreaks(uint32_t aStart, uint32_t aLength, - uint8_t* aBreakBefore); + virtual bool SetPotentialLineBreaks(Range aRange, uint8_t* aBreakBefore); /** * Called after SetCapitalization and SetPotentialLineBreaks * are done and before we request any data from the textrun. Also always diff --git a/layout/inspector/nsFontFaceList.cpp b/layout/inspector/nsFontFaceList.cpp index 57f7413d6c..5f9b0ecb48 100644 --- a/layout/inspector/nsFontFaceList.cpp +++ b/layout/inspector/nsFontFaceList.cpp @@ -60,7 +60,8 @@ nsresult nsFontFaceList::AddFontsFromTextRun(gfxTextRun* aTextRun, uint32_t aOffset, uint32_t aLength) { - gfxTextRun::GlyphRunIterator iter(aTextRun, aOffset, aLength); + gfxTextRun::Range range(aOffset, aOffset + aLength); + gfxTextRun::GlyphRunIterator iter(aTextRun, range); while (iter.NextRun()) { gfxFontEntry *fe = iter.GetGlyphRun()->mFont->GetFontEntry(); // if we have already listed this face, just make sure the match type is diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 51697a4095..28fbf4de7e 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -1023,9 +1023,7 @@ static nsBoundingMetrics MeasureTextRun(DrawTarget* aDrawTarget, gfxTextRun* aTextRun) { gfxTextRun::Metrics metrics = - aTextRun->MeasureText(0, aTextRun->GetLength(), - gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, - aDrawTarget, nullptr); + aTextRun->MeasureText(gfxFont::TIGHT_HINTED_OUTLINE_EXTENTS, aDrawTarget); nsBoundingMetrics bm; bm.leftBearing = NSToCoordFloor(metrics.mBoundingBox.X()); @@ -2150,9 +2148,8 @@ nsMathMLChar::PaintForeground(nsPresContext* aPresContext, // draw a single glyph (base size or size variant) // XXXfredw verify if mGlyphs[0] is non-null to workaround bug 973322. if (mGlyphs[0]) { - mGlyphs[0]->Draw(thebesContext, gfxPoint(0.0, mUnscaledAscent), - DrawMode::GLYPH_FILL, 0, mGlyphs[0]->GetLength(), - nullptr, nullptr, nullptr); + mGlyphs[0]->Draw(Range(mGlyphs[0]), gfxPoint(0.0, mUnscaledAscent), + gfxTextRun::DrawParams(thebesContext)); } break; case DRAW_PARTS: { @@ -2279,6 +2276,8 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext, mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing; unionRect.Inflate(oneDevPixel, oneDevPixel); + gfxTextRun::DrawParams params(aThebesContext); + ///////////////////////////////////// // draw top, middle, bottom for (i = 0; i <= 2; ++i) { @@ -2307,9 +2306,7 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext, } if (!clipRect.IsEmpty()) { AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect); - mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy), - DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(), - nullptr, nullptr, nullptr); + mGlyphs[i]->Draw(Range(mGlyphs[i]), gfxPoint(dx, dy), params); } } } @@ -2375,9 +2372,7 @@ nsMathMLChar::PaintVertically(nsPresContext* aPresContext, clipRect.height = std::min(bm.ascent + bm.descent, fillEnd - dy); AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect); dy += bm.ascent; - mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy), - DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(), - nullptr, nullptr, nullptr); + mGlyphs[3]->Draw(Range(mGlyphs[3]), gfxPoint(dx, dy), params); dy += bm.descent; } } @@ -2453,6 +2448,8 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext, nsRect unionRect = aRect; unionRect.Inflate(oneDevPixel, oneDevPixel); + gfxTextRun::DrawParams params(aThebesContext); + /////////////////////////// // draw left, middle, right for (i = 0; i <= 2; ++i) { @@ -2479,9 +2476,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext, } if (!clipRect.IsEmpty()) { AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect); - mGlyphs[i]->Draw(aThebesContext, gfxPoint(dx, dy), - DrawMode::GLYPH_FILL, 0, mGlyphs[i]->GetLength(), - nullptr, nullptr, nullptr); + mGlyphs[i]->Draw(Range(mGlyphs[i]), gfxPoint(dx, dy), params); } } } @@ -2545,9 +2540,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext, clipRect.width = std::min(bm.rightBearing - bm.leftBearing, fillEnd - dx); AutoPushClipRect clip(aThebesContext, oneDevPixel, clipRect); dx -= bm.leftBearing; - mGlyphs[3]->Draw(aThebesContext, gfxPoint(dx, dy), - DrawMode::GLYPH_FILL, 0, mGlyphs[3]->GetLength(), - nullptr, nullptr, nullptr); + mGlyphs[3]->Draw(Range(mGlyphs[3]), gfxPoint(dx, dy), params); dx += bm.rightBearing; } } diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h index 602d587ff8..1d3cc520e2 100644 --- a/layout/mathml/nsMathMLChar.h +++ b/layout/mathml/nsMathMLChar.h @@ -13,7 +13,7 @@ #include "nsRect.h" #include "nsString.h" #include "nsBoundingMetrics.h" -#include "gfxFont.h" +#include "gfxTextRun.h" class nsGlyphTable; class nsIFrame; @@ -85,6 +85,7 @@ struct nsGlyphCode { class nsMathMLChar { public: + typedef gfxTextRun::Range Range; typedef mozilla::gfx::DrawTarget DrawTarget; // constructor and destructor diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list index f754fc1c52..16ee8809a9 100644 --- a/layout/reftests/font-matching/reftest.list +++ b/layout/reftests/font-matching/reftest.list @@ -110,3 +110,14 @@ fuzzy-if(Mulet,103,144) == italic-oblique-6.html italic-oblique-ref.html fuzzy-if(Mulet,103,144) == italic-oblique-8.html italic-oblique-ref.html fuzzy-if(Mulet,103,144) == italic-oblique-9.html italic-oblique-ref.html != italic-oblique-kinnari.html italic-oblique-kinnari-ref.html + +# system font generic per-language tests, only works under OSX currently +random-if(!OSX) == system-generic-fallback-1.html system-generic-fallback-1-ref.html +random-if(!OSX||OSX<1008) == system-generic-fallback-2.html system-generic-fallback-2-ref.html +random-if(!OSX||OSX<1008) == system-generic-fallback-3.html system-generic-fallback-3-ref.html +random-if(!OSX||OSX<1008) == system-generic-fallback-4.html system-generic-fallback-4-ref.html +random-if(!OSX) != system-generic-fallback-ko.html system-generic-fallback-ja.html +random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-ja.html +random-if(!OSX) != system-generic-fallback-zh-cn.html system-generic-fallback-ja.html +random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-zh-cn.html + diff --git a/layout/reftests/font-matching/system-generic-fallback-1-ref.html b/layout/reftests/font-matching/system-generic-fallback-1-ref.html new file mode 100644 index 0000000000..84deb813a1 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-1-ref.html @@ -0,0 +1,39 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-1.html b/layout/reftests/font-matching/system-generic-fallback-1.html new file mode 100644 index 0000000000..d06d5259cb --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-1.html @@ -0,0 +1,39 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-2-ref.html b/layout/reftests/font-matching/system-generic-fallback-2-ref.html new file mode 100644 index 0000000000..efe6f93739 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-2-ref.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-2.html b/layout/reftests/font-matching/system-generic-fallback-2.html new file mode 100644 index 0000000000..2e1b02655c --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-2.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-3-ref.html b/layout/reftests/font-matching/system-generic-fallback-3-ref.html new file mode 100644 index 0000000000..0ddd8c5d94 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-3-ref.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-3.html b/layout/reftests/font-matching/system-generic-fallback-3.html new file mode 100644 index 0000000000..a704d234c4 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-3.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-4-ref.html b/layout/reftests/font-matching/system-generic-fallback-4-ref.html new file mode 100644 index 0000000000..5961caaf53 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-4-ref.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-4.html b/layout/reftests/font-matching/system-generic-fallback-4.html new file mode 100644 index 0000000000..d7ffee3e97 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-4.html @@ -0,0 +1,38 @@ + + + +system generic linked families + + + + + + + +
+

+

+

+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-ja.html b/layout/reftests/font-matching/system-generic-fallback-ja.html new file mode 100644 index 0000000000..844200111f --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-ja.html @@ -0,0 +1,33 @@ + + + +system generic linked families + + + + + + + +
+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-ko.html b/layout/reftests/font-matching/system-generic-fallback-ko.html new file mode 100644 index 0000000000..526ab817d8 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-ko.html @@ -0,0 +1,33 @@ + + + +system generic linked families + + + + + + + +
+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-zh-cn.html b/layout/reftests/font-matching/system-generic-fallback-zh-cn.html new file mode 100644 index 0000000000..afcabb396c --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-zh-cn.html @@ -0,0 +1,33 @@ + + + +system generic linked families + + + + + + + +
+

+
+ + + diff --git a/layout/reftests/font-matching/system-generic-fallback-zh-tw.html b/layout/reftests/font-matching/system-generic-fallback-zh-tw.html new file mode 100644 index 0000000000..64cc1aded5 --- /dev/null +++ b/layout/reftests/font-matching/system-generic-fallback-zh-tw.html @@ -0,0 +1,33 @@ + + + +system generic linked families + + + + + + + +
+

+
+ + + diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp index 19ea8f8809..cbad10ef0f 100644 --- a/layout/svg/SVGTextFrame.cpp +++ b/layout/svg/SVGTextFrame.cpp @@ -60,34 +60,16 @@ using namespace mozilla::gfx; * in original char indexes to skipped char indexes. * * @param aIterator The gfxSkipCharsIterator to use for the conversion. - * @param aOriginalOffset The original offset (input). - * @param aOriginalLength The original length (input). - * @param aSkippedOffset The skipped offset (output). - * @param aSkippedLength The skipped length (output). + * @param aOriginalOffset The original offset. + * @param aOriginalLength The original length. */ -static void +static gfxTextRun::Range ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator, - uint32_t aOriginalOffset, uint32_t aOriginalLength, - uint32_t& aSkippedOffset, uint32_t& aSkippedLength) + uint32_t aOriginalOffset, uint32_t aOriginalLength) { - aSkippedOffset = aIterator.ConvertOriginalToSkipped(aOriginalOffset); + uint32_t start = aIterator.ConvertOriginalToSkipped(aOriginalOffset); aIterator.AdvanceOriginal(aOriginalLength); - aSkippedLength = aIterator.GetSkippedOffset() - aSkippedOffset; -} - -/** - * Using the specified gfxSkipCharsIterator, converts an offset and length - * in original char indexes to skipped char indexes in place. - * - * @param aIterator The gfxSkipCharsIterator to use for the conversion. - * @param aOriginalOffset The offset to convert from original to skipped. - * @param aOriginalLength The length to convert from original to skipped. - */ -static void -ConvertOriginalToSkipped(gfxSkipCharsIterator& aIterator, - uint32_t& aOffset, uint32_t& aLength) -{ - ConvertOriginalToSkipped(aIterator, aOffset, aLength, aOffset, aLength); + return gfxTextRun::Range(start, aIterator.GetSkippedOffset()); } /** @@ -157,15 +139,11 @@ GetAscentAndDescentInAppUnits(nsTextFrame* aFrame, gfxSkipCharsIterator it = aFrame->EnsureTextRun(nsTextFrame::eInflated); gfxTextRun* textRun = aFrame->GetTextRun(nsTextFrame::eInflated); - uint32_t offset, length; - ConvertOriginalToSkipped(it, - aFrame->GetContentOffset(), - aFrame->GetContentLength(), - offset, length); + gfxTextRun::Range range = ConvertOriginalToSkipped( + it, aFrame->GetContentOffset(), aFrame->GetContentLength()); gfxTextRun::Metrics metrics = - textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, nullptr, - nullptr); + textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr); aAscent = metrics.mAscent; aDescent = metrics.mDescent; @@ -342,8 +320,7 @@ GetBaselinePosition(nsTextFrame* aFrame, { WritingMode writingMode = aFrame->GetWritingMode(); gfxTextRun::Metrics metrics = - aTextRun->MeasureText(0, aTextRun->GetLength(), gfxFont::LOOSE_INK_EXTENTS, - nullptr, nullptr); + aTextRun->MeasureText(gfxFont::LOOSE_INK_EXTENTS, nullptr); switch (aDominantBaseline) { case NS_STYLE_DOMINANT_BASELINE_HANGING: @@ -386,7 +363,7 @@ GetBaselinePosition(nsTextFrame* aFrame, } /** - * For a given text run, returns the number of skipped characters that comprise + * For a given text run, returns the range of skipped characters that comprise * the ligature group and/or cluster that includes the character represented * by the specified gfxSkipCharsIterator. * @@ -395,8 +372,8 @@ GetBaselinePosition(nsTextFrame* aFrame, * @param aIterator The gfxSkipCharsIterator to use for the current position * in the text run. */ -static uint32_t -ClusterLength(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator) +static gfxTextRun::Range +ClusterRange(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator) { uint32_t start = aIterator.GetSkippedOffset(); uint32_t end = start + 1; @@ -405,7 +382,7 @@ ClusterLength(gfxTextRun* aTextRun, const gfxSkipCharsIterator& aIterator) !aTextRun->IsClusterStart(end))) { end++; } - return end - start; + return gfxTextRun::Range(start, end); } /** @@ -482,6 +459,8 @@ namespace mozilla { */ struct TextRenderedRun { + typedef gfxTextRun::Range Range; + /** * Constructs a TextRenderedRun that is uninitialized except for mFrame * being null. @@ -939,17 +918,15 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated); // Get the content range for this rendered run. - uint32_t offset, length; - ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength, - offset, length); - if (length == 0) { + Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, + mTextFrameContentLength); + if (range.Length() == 0) { return r; } // Measure that range. gfxTextRun::Metrics metrics = - textRun->MeasureText(offset, length, gfxFont::LOOSE_INK_EXTENTS, - nullptr, nullptr); + textRun->MeasureText(range, gfxFont::LOOSE_INK_EXTENTS, nullptr, nullptr); // Make sure it includes the font-box. gfxRect fontBox(0, -metrics.mAscent, metrics.mAdvanceWidth, metrics.mAscent + metrics.mDescent); @@ -962,7 +939,7 @@ TextRenderedRun::GetRunUserSpaceRect(nsPresContext* aContext, gfxFloat x, width; if (aFlags & eNoHorizontalOverflow) { x = 0.0; - width = textRun->GetAdvanceWidth(offset, length, nullptr); + width = textRun->GetAdvanceWidth(range, nullptr); } else { x = metrics.mBoundingBox.x; width = metrics.mBoundingBox.width; @@ -1059,13 +1036,12 @@ TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge, // Get the covered content offset/length for this rendered run in skipped // characters, since that is what GetAdvanceWidth expects. - uint32_t runOffset, runLength, frameOffset, frameLength; - ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength, - runOffset, runLength); + Range runRange = ConvertOriginalToSkipped(it, mTextFrameContentOffset, + mTextFrameContentLength); // Get the offset/length of the whole nsTextFrame. - frameOffset = mFrame->GetContentOffset(); - frameLength = mFrame->GetContentLength(); + uint32_t frameOffset = mFrame->GetContentOffset(); + uint32_t frameLength = mFrame->GetContentLength(); // Trim the whole-nsTextFrame offset/length to remove any leading/trailing // white space, as the nsTextFrame when painting does not include them when @@ -1076,19 +1052,17 @@ TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge, // Convert the trimmed whole-nsTextFrame offset/length into skipped // characters. - ConvertOriginalToSkipped(it, frameOffset, frameLength); + Range frameRange = ConvertOriginalToSkipped(it, frameOffset, frameLength); // Measure the advance width in the text run between the start of // frame's content and the start of the rendered run's content, - nscoord startEdge = - textRun->GetAdvanceWidth(frameOffset, runOffset - frameOffset, nullptr); + nscoord startEdge = textRun-> + GetAdvanceWidth(Range(frameRange.start, runRange.start), nullptr); // and between the end of the rendered run's content and the end // of the frame's content. - nscoord endEdge = - textRun->GetAdvanceWidth(runOffset + runLength, - frameOffset + frameLength - (runOffset + runLength), - nullptr); + nscoord endEdge = textRun-> + GetAdvanceWidth(Range(runRange.end, frameRange.end), nullptr); if (textRun->IsRightToLeft()) { aVisIStartEdge = endEdge; @@ -1105,11 +1079,10 @@ TextRenderedRun::GetAdvanceWidth() const gfxSkipCharsIterator it = mFrame->EnsureTextRun(nsTextFrame::eInflated); gfxTextRun* textRun = mFrame->GetTextRun(nsTextFrame::eInflated); - uint32_t offset, length; - ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength, - offset, length); + Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, + mTextFrameContentLength); - return textRun->GetAdvanceWidth(offset, length, nullptr); + return textRun->GetAdvanceWidth(range, nullptr); } int32_t @@ -1160,12 +1133,10 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext, // Next check that the point lies horizontally within the left and right // edges of the text. - uint32_t offset, length; - ConvertOriginalToSkipped(it, mTextFrameContentOffset, mTextFrameContentLength, - offset, length); + Range range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, + mTextFrameContentLength); gfxFloat runAdvance = - aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length, - nullptr)); + aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr)); gfxFloat pos = writingMode.IsVertical() ? p.y : p.x; if (pos < 0 || pos >= runAdvance) { @@ -1177,10 +1148,9 @@ TextRenderedRun::GetCharNumAtPosition(nsPresContext* aContext, // support letter-spacing and word-spacing. bool rtl = textRun->IsRightToLeft(); for (int32_t i = mTextFrameContentLength - 1; i >= 0; i--) { - ConvertOriginalToSkipped(it, mTextFrameContentOffset, i, offset, length); + range = ConvertOriginalToSkipped(it, mTextFrameContentOffset, i); gfxFloat advance = - aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(offset, length, - nullptr)); + aContext->AppUnitsToGfxUnits(textRun->GetAdvanceWidth(range, nullptr)); if ((rtl && pos < runAdvance - advance) || (!rtl && pos >= advance)) { return i; @@ -2138,6 +2108,8 @@ TextRenderedRunIterator::First() */ class CharIterator { + typedef gfxTextRun::Range Range; + public: /** * Values for the aFilter argument of the constructor, to indicate which @@ -2629,12 +2601,12 @@ CharIterator::GetGlyphAdvance(nsPresContext* aContext) const GetOriginalGlyphOffsets(offset, length); gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated); - ConvertOriginalToSkipped(it, offset, length); + Range range = ConvertOriginalToSkipped(it, offset, length); float cssPxPerDevPx = aContext-> AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel()); - gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr); + gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr); return aContext->AppUnitsToGfxUnits(advance) * mLengthAdjustScaleFactor * cssPxPerDevPx; } @@ -2645,8 +2617,9 @@ CharIterator::GetAdvance(nsPresContext* aContext) const float cssPxPerDevPx = aContext-> AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel()); - gfxFloat advance = - mTextRun->GetAdvanceWidth(mSkipCharsIterator.GetSkippedOffset(), 1, nullptr); + uint32_t offset = mSkipCharsIterator.GetSkippedOffset(); + gfxFloat advance = mTextRun-> + GetAdvanceWidth(Range(offset, offset + 1), nullptr); return aContext->AppUnitsToGfxUnits(advance) * mLengthAdjustScaleFactor * cssPxPerDevPx; } @@ -2662,12 +2635,12 @@ CharIterator::GetGlyphPartialAdvance(uint32_t aPartLength, length = aPartLength; gfxSkipCharsIterator it = TextFrame()->EnsureTextRun(nsTextFrame::eInflated); - ConvertOriginalToSkipped(it, offset, length); + Range range = ConvertOriginalToSkipped(it, offset, length); float cssPxPerDevPx = aContext-> AppUnitsToFloatCSSPixels(aContext->AppUnitsPerDevPixel()); - gfxFloat advance = mTextRun->GetAdvanceWidth(offset, length, nullptr); + gfxFloat advance = mTextRun->GetAdvanceWidth(range, nullptr); return aContext->AppUnitsToGfxUnits(advance) * mLengthAdjustScaleFactor * cssPxPerDevPx; } @@ -4226,10 +4199,10 @@ SVGTextFrame::GetSubStringLength(nsIContent* aContent, gfxSkipCharsIterator it = run.mFrame->EnsureTextRun(nsTextFrame::eInflated); gfxTextRun* textRun = run.mFrame->GetTextRun(nsTextFrame::eInflated); - ConvertOriginalToSkipped(it, offset, length); + Range range = ConvertOriginalToSkipped(it, offset, length); // Accumulate the advance. - textLength += textRun->GetAdvanceWidth(offset, length, nullptr); + textLength += textRun->GetAdvanceWidth(range, nullptr); } run = it.Next(); @@ -4728,8 +4701,9 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions) !it.IsOriginalCharSkipped() && (!textRun->IsLigatureGroupStart(it.GetSkippedOffset()) || !textRun->IsClusterStart(it.GetSkippedOffset()))) { - nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), 1, - nullptr); + uint32_t offset = it.GetSkippedOffset(); + nscoord advance = textRun-> + GetAdvanceWidth(Range(offset, offset + 1), nullptr); (textRun->IsVertical() ? position.y : position.x) += textRun->IsRightToLeft() ? -advance : advance; aPositions.AppendElement(lastPosition); @@ -4743,9 +4717,8 @@ SVGTextFrame::DetermineCharPositions(nsTArray& aPositions) textRun->IsLigatureGroupStart(it.GetSkippedOffset()) && textRun->IsClusterStart(it.GetSkippedOffset())) { // A real visible character. - uint32_t length = ClusterLength(textRun, it); - nscoord advance = textRun->GetAdvanceWidth(it.GetSkippedOffset(), - length, nullptr); + nscoord advance = textRun-> + GetAdvanceWidth(ClusterRange(textRun, it), nullptr); (textRun->IsVertical() ? position.y : position.x) += textRun->IsRightToLeft() ? -advance : advance; lastPosition = position; diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h index f94ea570a3..72a822af46 100644 --- a/layout/svg/SVGTextFrame.h +++ b/layout/svg/SVGTextFrame.h @@ -12,6 +12,7 @@ #include "gfxMatrix.h" #include "gfxRect.h" #include "gfxSVGGlyphs.h" +#include "gfxTextRun.h" #include "nsIContent.h" // for GetContent #include "nsStubMutationObserver.h" #include "nsSVGPaintServerFrame.h" @@ -259,6 +260,7 @@ class SVGTextFrame final : public SVGTextFrameBase friend class MutationObserver; friend class nsDisplaySVGText; + typedef gfxTextRun::Range Range; typedef mozilla::gfx::DrawTarget DrawTarget; typedef mozilla::gfx::Path Path; typedef mozilla::gfx::Point Point; diff --git a/layout/xul/nsXULTooltipListener.cpp b/layout/xul/nsXULTooltipListener.cpp index 613389e16d..8117ad3f44 100644 --- a/layout/xul/nsXULTooltipListener.cpp +++ b/layout/xul/nsXULTooltipListener.cpp @@ -358,7 +358,12 @@ nsXULTooltipListener::CheckTreeBodyMove(nsIDOMMouseEvent* aMouseEvent) // determine if we are going to need a titletip // XXX check the disabletitletips attribute on the tree content mNeedTitletip = false; - if (row >= 0 && obj.EqualsLiteral("text")) { + int16_t colType = -1; + if (col) { + col->GetType(&colType); + } + if (row >= 0 && obj.EqualsLiteral("text") && + colType != nsITreeColumn::TYPE_PASSWORD) { obx->IsCellCropped(row, col, &mNeedTitletip); } diff --git a/layout/xul/tree/nsITreeColumns.idl b/layout/xul/tree/nsITreeColumns.idl index 9b27ce25e8..a601f3776b 100644 --- a/layout/xul/tree/nsITreeColumns.idl +++ b/layout/xul/tree/nsITreeColumns.idl @@ -32,6 +32,7 @@ interface nsITreeColumn : nsISupports const short TYPE_TEXT = 1; const short TYPE_CHECKBOX = 2; const short TYPE_PROGRESSMETER = 3; + const short TYPE_PASSWORD = 4; readonly attribute short type; nsITreeColumn getNext(); diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp index 86ca9a5fa7..27a7a4a43d 100644 --- a/layout/xul/tree/nsTreeBodyFrame.cpp +++ b/layout/xul/tree/nsTreeBodyFrame.cpp @@ -66,6 +66,7 @@ #include "nsIScriptableRegion.h" #include #include "ScrollbarActivity.h" +#include "../../editor/libeditor/nsTextEditRules.h" #ifdef ACCESSIBILITY #include "nsAccessibilityService.h" @@ -3366,6 +3367,7 @@ nsTreeBodyFrame::PaintCell(int32_t aRowIndex, if (dirtyRect.IntersectRect(aDirtyRect, elementRect)) { switch (aColumn->GetType()) { case nsITreeColumn::TYPE_TEXT: + case nsITreeColumn::TYPE_PASSWORD: PaintText(aRowIndex, aColumn, elementRect, aPresContext, aRenderingContext, aDirtyRect, currX); break; case nsITreeColumn::TYPE_CHECKBOX: @@ -3672,6 +3674,11 @@ nsTreeBodyFrame::PaintText(int32_t aRowIndex, // Now obtain the text for our cell. nsAutoString text; mView->GetCellText(aRowIndex, aColumn, text); + + if (aColumn->Type() == nsITreeColumn::TYPE_PASSWORD) { + nsTextEditRules::FillBufWithPWChars(&text, text.Length()); + } + // We're going to paint this text so we need to ensure bidi is enabled if // necessary CheckTextForBidi(text); diff --git a/layout/xul/tree/nsTreeColumns.cpp b/layout/xul/tree/nsTreeColumns.cpp index 01dace53ab..18424bca4f 100644 --- a/layout/xul/tree/nsTreeColumns.cpp +++ b/layout/xul/tree/nsTreeColumns.cpp @@ -321,11 +321,13 @@ nsTreeColumn::Invalidate() // Figure out our column type. Default type is text. mType = nsITreeColumn::TYPE_TEXT; static nsIContent::AttrValuesArray typestrings[] = - {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, nullptr}; + {&nsGkAtoms::checkbox, &nsGkAtoms::progressmeter, &nsGkAtoms::password, + nullptr}; switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type, typestrings, eCaseMatters)) { case 0: mType = nsITreeColumn::TYPE_CHECKBOX; break; case 1: mType = nsITreeColumn::TYPE_PROGRESSMETER; break; + case 2: mType = nsITreeColumn::TYPE_PASSWORD; break; } // Fetch the crop style. diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 55546fc3ee..e8bcbb8500 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -10,6 +10,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" #include "mozilla/HashFunctions.h" +#include "mozilla/UniquePtrExtensions.h" #include "nsXULAppAPI.h" @@ -238,7 +239,6 @@ Preferences::SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeO } } if (gObserverTable) { - n += aMallocSizeOf(gObserverTable); n += gObserverTable->ShallowSizeOfIncludingThis(aMallocSizeOf); for (auto iter = gObserverTable->Iter(); !iter.Done(); iter.Next()) { n += iter.Key()->mPrefName.SizeOfExcludingThisIfUnshared(aMallocSizeOf); @@ -942,25 +942,23 @@ Preferences::WritePrefFile(nsIFile* aFile) if (NS_FAILED(rv)) return rv; - nsAutoArrayPtr valueArray(new char*[gHashTable->EntryCount()]); - memset(valueArray, 0, gHashTable->EntryCount() * sizeof(char*)); - // get the lines that we're supposed to be writing to the file - pref_savePrefs(gHashTable, valueArray); + UniquePtr valueArray = pref_savePrefs(gHashTable); /* Sort the preferences to make a readable file on disk */ - NS_QuickSort(valueArray, gHashTable->EntryCount(), sizeof(char *), + NS_QuickSort(valueArray.get(), gHashTable->EntryCount(), sizeof(char *), pref_CompareStrings, nullptr); // write out the file header outStream->Write(outHeader, sizeof(outHeader) - 1, &writeAmount); - char** walker = valueArray; - for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++, walker++) { - if (*walker) { - outStream->Write(*walker, strlen(*walker), &writeAmount); + for (uint32_t valueIdx = 0; valueIdx < gHashTable->EntryCount(); valueIdx++) { + char*& pref = valueArray[valueIdx]; + if (pref) { + outStream->Write(pref, strlen(pref), &writeAmount); outStream->Write(NS_LINEBREAK, NS_LINEBREAK_LEN, &writeAmount); - NS_Free(*walker); + free(pref); + pref = nullptr; } } @@ -995,7 +993,7 @@ static nsresult openPrefFile(nsIFile* aFile) NS_ENSURE_TRUE(fileSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG); uint32_t fileSize = (uint32_t)fileSize64; - nsAutoArrayPtr fileBuffer(new char[fileSize]); + auto fileBuffer = MakeUniqueFallible(fileSize); if (fileBuffer == nullptr) return NS_ERROR_OUT_OF_MEMORY; @@ -1008,10 +1006,10 @@ static nsresult openPrefFile(nsIFile* aFile) uint32_t offset = 0; for (;;) { uint32_t amtRead = 0; - rv = inStr->Read((char*)fileBuffer, fileSize, &amtRead); + rv = inStr->Read(fileBuffer.get(), fileSize, &amtRead); if (NS_FAILED(rv) || amtRead == 0) break; - if (!PREF_ParseBuf(&ps, fileBuffer, amtRead)) + if (!PREF_ParseBuf(&ps, fileBuffer.get(), amtRead)) rv2 = NS_ERROR_FILE_CORRUPTED; offset += amtRead; if (offset == fileSize) { diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5ca5b20b48..6f8fa43c94 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -127,22 +127,15 @@ pref("dom.indexedDB.logging.details", true); // Enable profiler marks for indexedDB events. pref("dom.indexedDB.logging.profiler-marks", false); +// Whether or not File Handle is enabled. +pref("dom.fileHandle.enabled", true); + // Whether or not selection events are enabled pref("dom.select_events.enabled", true); // Whether or not selection events on text controls are enabled pref("dom.select_events.textcontrols.enabled", true); -// Whether or not File Handle is enabled. -pref("dom.fileHandle.enabled", true); - -// Whether or not the Permissions API is enabled. -#ifdef NIGHTLY_BUILD -pref("dom.permissions.enabled", true); -#else -pref("dom.permissions.enabled", false); -#endif - // Whether or not Web Workers are enabled. pref("dom.workers.enabled", true); // The number of workers per domain allowed to run concurrently. diff --git a/modules/libpref/prefapi.cpp b/modules/libpref/prefapi.cpp index dd2776987e..1caa053861 100644 --- a/modules/libpref/prefapi.cpp +++ b/modules/libpref/prefapi.cpp @@ -318,9 +318,12 @@ pref_SetPref(const dom::PrefSetting& aPref) return rv; } -void -pref_savePrefs(PLDHashTable* aTable, char** aPrefArray) +UniquePtr +pref_savePrefs(PLDHashTable* aTable) { + auto savedPrefs = MakeUnique(aTable->EntryCount()); + memset(savedPrefs.get(), 0, aTable->EntryCount() * sizeof(char*)); + int32_t j = 0; for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) { auto pref = static_cast(iter.Get()); @@ -360,12 +363,14 @@ pref_savePrefs(PLDHashTable* aTable, char** aPrefArray) nsAutoCString prefName; str_escape(pref->key, prefName); - aPrefArray[j++] = ToNewCString(prefPrefix + + savedPrefs[j++] = ToNewCString(prefPrefix + prefName + NS_LITERAL_CSTRING("\", ") + prefValue + NS_LITERAL_CSTRING(");")); } + + return savedPrefs; } static void diff --git a/modules/libpref/prefapi_private_data.h b/modules/libpref/prefapi_private_data.h index 45b6a4d733..f91b0d6c74 100644 --- a/modules/libpref/prefapi_private_data.h +++ b/modules/libpref/prefapi_private_data.h @@ -9,6 +9,7 @@ #define prefapi_private_data_h #include "mozilla/MemoryReporting.h" +#include "mozilla/UniquePtr.h" extern PLDHashTable* gHashTable; extern bool gDirty; @@ -19,8 +20,8 @@ class PrefSetting; } // namespace dom } // namespace mozilla -void -pref_savePrefs(PLDHashTable* aTable, char** aPrefArray); +mozilla::UniquePtr +pref_savePrefs(PLDHashTable* aTable); nsresult pref_SetPref(const mozilla::dom::PrefSetting& aPref); diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini index 1bf9c4148b..b519769802 100644 --- a/netwerk/test/mochitests/mochitest.ini +++ b/netwerk/test/mochitests/mochitest.ini @@ -27,6 +27,7 @@ skip-if = e10s [test_signed_web_packaged_app.html] skip-if = e10s || buildapp != 'browser' [test_web_packaged_app.html] +skip-if = buildapp != 'mulet' [test_signed_web_packaged_app_origin.html] skip-if = e10s || buildapp != 'browser' skip-if = buildapp == 'b2g' #no ssl support diff --git a/testing/mochitest/tests/Harness_sanity/mochitest.ini b/testing/mochitest/tests/Harness_sanity/mochitest.ini index 113a307eec..f3c2c5f24b 100644 --- a/testing/mochitest/tests/Harness_sanity/mochitest.ini +++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini @@ -1,5 +1,5 @@ [DEFAULT] -skip-if = buildapp == 'mulet' || buildapp == 'b2g' +skip-if = buildapp == 'b2g' [test_TestsRunningAfterSimpleTestFinish.html] skip-if = true #depends on fix for bug 1048446 [test_add_task.html] @@ -30,7 +30,7 @@ skip-if = toolkit == 'android' || e10s #No test app installed [test_sanity_cleanup.html] [test_sanity_cleanup2.html] [test_sanityEventUtils.html] -skip-if = toolkit == 'android' #bug 688052 +skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 688052 [test_sanitySimpletest.html] skip-if = toolkit == 'android' #bug 688052 [test_sanity_manifest.html] diff --git a/testing/web-platform/mozilla/meta/MANIFEST.json b/testing/web-platform/mozilla/meta/MANIFEST.json index 5aad985824..72557df142 100644 --- a/testing/web-platform/mozilla/meta/MANIFEST.json +++ b/testing/web-platform/mozilla/meta/MANIFEST.json @@ -505,12 +505,6 @@ "url": "/_mozilla/service-workers/service-worker/state.https.html" } ], - "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html": [ - { - "path": "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html", - "url": "/_mozilla/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html" - } - ], "service-workers/service-worker/synced-state.https.html": [ { "path": "service-workers/service-worker/synced-state.https.html", @@ -576,6 +570,12 @@ "path": "service-workers/service-worker/worker-interception.https.html", "url": "/_mozilla/service-workers/service-worker/worker-interception.https.html" } + ], + "service-workers/service-worker/xhr.https.html": [ + { + "path": "service-workers/service-worker/xhr.https.html", + "url": "/_mozilla/service-workers/service-worker/xhr.https.html" + } ] } }, @@ -585,4 +585,4 @@ "rev": null, "url_base": "/_mozilla/", "version": 2 -} \ No newline at end of file +} diff --git a/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini b/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini deleted file mode 100644 index 3b7d472785..0000000000 --- a/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini +++ /dev/null @@ -1,9 +0,0 @@ -[sync-xhr-doesnt-deadlock.https.html] - type: testharness - expected: - if debug and (os == "win") and (version == "5.1.2600") and (processor == "x86") and (bits == 32): CRASH - if debug and (os == "win") and (version == "6.2.9200") and (processor == "x86_64") and (bits == 64): CRASH - if debug and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): CRASH - [Verify SyncXHR does not deadlock] - expected: FAIL - diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html deleted file mode 100644 index 0fa7291162..0000000000 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html +++ /dev/null @@ -1,12 +0,0 @@ - -Service Worker: SyncXHR doesn't deadlock iframe - diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data deleted file mode 100644 index b6fc4c620b..0000000000 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data +++ /dev/null @@ -1 +0,0 @@ -hello \ No newline at end of file diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js deleted file mode 100644 index 3e9093de5a..0000000000 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js +++ /dev/null @@ -1,5 +0,0 @@ -self.onfetch = function(event) { - if (event.request.url.indexOf('sync-xhr-doesnt-deadlock.data') == -1) - return; - event.respondWith(fetch('404resource?bustcache=' + Date.now())); -}; diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js new file mode 100644 index 0000000000..387c4a48ed --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js @@ -0,0 +1,6 @@ +self.addEventListener('activate', function(event) { + event.waitUntil(clients.claim()); + }); +self.addEventListener('message', function(event) { + event.data.port.postMessage({xhr: !!("XMLHttpRequest" in self)}); + }); diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html deleted file mode 100644 index 357cf9d5a5..0000000000 --- a/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html +++ /dev/null @@ -1,23 +0,0 @@ - -Service Worker: SyncXHR doesn't deadlock - - - - diff --git a/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html b/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html new file mode 100644 index 0000000000..c03f1c955f --- /dev/null +++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html @@ -0,0 +1,34 @@ + +Service Worker: XHR doesn't exist + + + + + diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 32fb257e06..dcf1302802 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -270,6 +270,13 @@ "kind": "boolean", "description": "Was Fetch request initiated from the main thread?" }, + "FORCED_DEVICE_RESET_REASON": { + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 50, + "releaseChannelCollection": "opt-out", + "description": "GPU Forced Device Reset Reason (OpenSharedHandle)" + }, "FORGET_SKIPPABLE_MAX": { "expires_in_version": "never", "kind": "exponential", diff --git a/toolkit/content/widgets/tree.xml b/toolkit/content/widgets/tree.xml index 11a5695ec0..448b7f60b8 100644 --- a/toolkit/content/widgets/tree.xml +++ b/toolkit/content/widgets/tree.xml @@ -341,8 +341,10 @@ return false; if (row < 0 || row >= this.view.rowCount || !column) return false; - if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT || - column.cycler || !this.view.isEditable(row, column)) + if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT && + column.type != Components.interfaces.nsITreeColumn.TYPE_PASSWORD) + return false; + if (column.cycler || !this.view.isEditable(row, column)) return false; // Beyond this point, we are going to edit the cell. diff --git a/toolkit/devtools/apps/tests/mochitest.ini b/toolkit/devtools/apps/tests/mochitest.ini index d640516174..b7ab3bef86 100644 --- a/toolkit/devtools/apps/tests/mochitest.ini +++ b/toolkit/devtools/apps/tests/mochitest.ini @@ -1,9 +1,8 @@ [DEFAULT] skip-if = e10s +skip-if = (buildapp != 'b2g' && buildapp != 'mulet') support-files = debugger-protocol-helper.js redirect.sjs [test_webapps_actor.html] -# The mochitest doesn't work on fennec yet -skip-if = toolkit == 'android' diff --git a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp index c053d29f08..5718e86ab8 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp @@ -53,6 +53,7 @@ using namespace mozilla; using namespace mozilla::dom; static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr; +static bool sAllowOfflineCache = true; nsTHashtable* nsOfflineCacheUpdateService::mAllowedDomains = nullptr; @@ -246,6 +247,10 @@ nsOfflineCacheUpdateService::nsOfflineCacheUpdateService() , mUpdateRunning(false) , mLowFreeSpace(false) { + MOZ_ASSERT(NS_IsMainThread()); + Preferences::AddBoolVarCache(&sAllowOfflineCache, + "browser.cache.offline.enable", + true); } nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService() @@ -604,6 +609,10 @@ OfflineAppPermForPrincipal(nsIPrincipal *aPrincipal, { *aAllowed = false; + if (!sAllowOfflineCache) { + return NS_OK; + } + if (!aPrincipal) return NS_ERROR_INVALID_ARG; @@ -696,6 +705,10 @@ nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow, { nsresult rv; + if (!sAllowOfflineCache) { + return NS_ERROR_NOT_AVAILABLE; + } + if (GeckoProcessType_Default != XRE_GetProcessType()) { ContentChild* child = ContentChild::GetSingleton(); diff --git a/xpcom/ds/StickyTimeDuration.h b/xpcom/ds/StickyTimeDuration.h index 750e813ea8..39a887dbce 100644 --- a/xpcom/ds/StickyTimeDuration.h +++ b/xpcom/ds/StickyTimeDuration.h @@ -159,7 +159,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA, // return -Forever if the signs differ, or +Forever otherwise. if (aA == INT64_MAX || aA == INT64_MIN || aB == INT64_MAX || aB == INT64_MIN) { - return (aA >= 0) ^ (aB >= 0) ? INT64_MAX : INT64_MIN; + return (aA >= 0) ^ (aB >= 0) ? INT64_MIN : INT64_MAX; } return aA * aB; @@ -177,7 +177,7 @@ StickyTimeDurationValueCalculator::Multiply(int64_t aA, double aB) // +/-Forever or +/-Infinity, then return -Forever if the signs differ, // or +Forever otherwise. if (aA == INT64_MAX || aA == INT64_MIN || IsInfinite(aB)) { - return (aA >= 0) ^ (aB >= 0.0) ? INT64_MAX : INT64_MIN; + return (aA >= 0) ^ (aB >= 0.0) ? INT64_MIN : INT64_MAX; } return aA * aB; diff --git a/xpcom/ds/nsHashPropertyBag.cpp b/xpcom/ds/nsHashPropertyBag.cpp index 32575487f6..6f9fc8dec3 100644 --- a/xpcom/ds/nsHashPropertyBag.cpp +++ b/xpcom/ds/nsHashPropertyBag.cpp @@ -160,7 +160,7 @@ IMPL_GETSETPROPERTY_AS(Bool, bool) NS_IMETHODIMP nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp, - nsAString& aResult) + nsAString& aResult) { nsIVariant* v = mPropertyHash.GetWeak(aProp); if (!v) { @@ -171,7 +171,7 @@ nsHashPropertyBagBase::GetPropertyAsAString(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp, - nsACString& aResult) + nsACString& aResult) { nsIVariant* v = mPropertyHash.GetWeak(aProp); if (!v) { @@ -182,7 +182,7 @@ nsHashPropertyBagBase::GetPropertyAsACString(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp, - nsACString& aResult) + nsACString& aResult) { nsIVariant* v = mPropertyHash.GetWeak(aProp); if (!v) { @@ -193,8 +193,8 @@ nsHashPropertyBagBase::GetPropertyAsAUTF8String(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp, - const nsIID& aIID, - void** aResult) + const nsIID& aIID, + void** aResult) { nsIVariant* v = mPropertyHash.GetWeak(aProp); if (!v) { @@ -215,7 +215,7 @@ nsHashPropertyBagBase::GetPropertyAsInterface(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp, - const nsAString& aValue) + const nsAString& aValue) { nsCOMPtr var = new nsVariant(); var->SetAsAString(aValue); @@ -224,7 +224,7 @@ nsHashPropertyBagBase::SetPropertyAsAString(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp, - const nsACString& aValue) + const nsACString& aValue) { nsCOMPtr var = new nsVariant(); var->SetAsACString(aValue); @@ -233,7 +233,7 @@ nsHashPropertyBagBase::SetPropertyAsACString(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp, - const nsACString& aValue) + const nsACString& aValue) { nsCOMPtr var = new nsVariant(); var->SetAsAUTF8String(aValue); @@ -242,7 +242,7 @@ nsHashPropertyBagBase::SetPropertyAsAUTF8String(const nsAString& aProp, NS_IMETHODIMP nsHashPropertyBagBase::SetPropertyAsInterface(const nsAString& aProp, - nsISupports* aValue) + nsISupports* aValue) { nsCOMPtr var = new nsVariant(); var->SetAsISupports(aValue); diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index 0db4b59326..1c99fabaad 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -49,9 +49,9 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, size_t mReferentCount; }; - size_t numStrong = 0; - size_t numWeakAlive = 0; - size_t numWeakDead = 0; + size_t totalNumStrong = 0; + size_t totalNumWeakAlive = 0; + size_t totalNumWeakDead = 0; nsTArray suspectObservers; for (auto iter = mObserverTopicTable.Iter(); !iter.Done(); iter.Next()) { @@ -60,26 +60,34 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, continue; } + size_t topicNumStrong = 0; + size_t topicNumWeakAlive = 0; + size_t topicNumWeakDead = 0; + nsTArray& observers = observerList->mObservers; for (uint32_t i = 0; i < observers.Length(); i++) { if (observers[i].isWeakRef) { nsCOMPtr observerRef( do_QueryReferent(observers[i].asWeak())); if (observerRef) { - numWeakAlive++; + topicNumWeakAlive++; } else { - numWeakDead++; + topicNumWeakDead++; } } else { - numStrong++; + topicNumStrong++; } } + totalNumStrong += topicNumStrong; + totalNumWeakAlive += topicNumWeakAlive; + totalNumWeakDead += topicNumWeakDead; + // Keep track of topics that have a suspiciously large number // of referents (symptom of leaks). - size_t total = numStrong + numWeakAlive + numWeakDead; - if (total > kSuspectReferentCount) { - SuspectObserver suspect(observerList->GetKey(), total); + size_t topicTotal = topicNumStrong + topicNumWeakAlive + topicNumWeakDead; + if (topicTotal > kSuspectReferentCount) { + SuspectObserver suspect(observerList->GetKey(), topicTotal); suspectObservers.AppendElement(suspect); } } @@ -107,7 +115,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, rv = aHandleReport->Callback( /* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/strong"), - KIND_OTHER, UNITS_COUNT, numStrong, + KIND_OTHER, UNITS_COUNT, totalNumStrong, NS_LITERAL_CSTRING("The number of strong references held by the " "observer service."), aData); @@ -119,7 +127,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, rv = aHandleReport->Callback( /* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/alive"), - KIND_OTHER, UNITS_COUNT, numWeakAlive, + KIND_OTHER, UNITS_COUNT, totalNumWeakAlive, NS_LITERAL_CSTRING("The number of weak references held by the " "observer service that are still alive."), aData); @@ -131,7 +139,7 @@ nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport, rv = aHandleReport->Callback( /* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/dead"), - KIND_OTHER, UNITS_COUNT, numWeakDead, + KIND_OTHER, UNITS_COUNT, totalNumWeakDead, NS_LITERAL_CSTRING("The number of weak references held by the " "observer service that are dead."), aData); diff --git a/xpcom/ds/nsPersistentProperties.cpp b/xpcom/ds/nsPersistentProperties.cpp index 67bdb473a0..69fef91097 100644 --- a/xpcom/ds/nsPersistentProperties.cpp +++ b/xpcom/ds/nsPersistentProperties.cpp @@ -523,11 +523,11 @@ nsPersistentProperties::SetStringProperty(const nsACString& aKey, { const nsAFlatCString& flatKey = PromiseFlatCString(aKey); auto entry = static_cast - (mTable.Add(flatKey.get(), mozilla::fallible)); + (mTable.Add(flatKey.get())); if (entry->mKey) { aOldValue = entry->mValue; - NS_WARNING(nsPrintfCString("the property %s already exists\n", + NS_WARNING(nsPrintfCString("the property %s already exists", flatKey.get()).get()); } else { aOldValue.Truncate(); diff --git a/xpcom/ds/nsSupportsArray.cpp b/xpcom/ds/nsSupportsArray.cpp index 0d1696e227..f20dd614e9 100644 --- a/xpcom/ds/nsSupportsArray.cpp +++ b/xpcom/ds/nsSupportsArray.cpp @@ -189,6 +189,9 @@ nsSupportsArray::Read(nsIObjectInputStream* aStream) uint32_t newArraySize; rv = aStream->Read32(&newArraySize); + if (NS_FAILED(rv)) { + return rv; + } if (newArraySize <= kAutoArraySize) { if (mArray != mAutoArray) { diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp index c9e68b7c0a..f75b51b8cc 100644 --- a/xpcom/ds/nsWindowsRegKey.cpp +++ b/xpcom/ds/nsWindowsRegKey.cpp @@ -310,7 +310,7 @@ nsWindowsRegKey::ReadStringValue(const nsAString& aName, nsAString& aResult) // This must be a string type in order to fetch the value as a string. // We're being a bit forgiving here by allowing types other than REG_SZ. - if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) { + if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) { return NS_ERROR_FAILURE; } diff --git a/xpcom/tests/unit/test_windows_registry.js b/xpcom/tests/unit/test_windows_registry.js new file mode 100644 index 0000000000..9a17678f83 --- /dev/null +++ b/xpcom/tests/unit/test_windows_registry.js @@ -0,0 +1,205 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ + +/* 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/. */ + +const Cr = Components.results; +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; +const CC = Components.Constructor; + +const nsIWindowsRegKey = Ci.nsIWindowsRegKey; +let regKeyComponent = Cc["@mozilla.org/windows-registry-key;1"]; + +function run_test() +{ + //* create a key structure in a spot that's normally writable (somewhere under HKCU). + let testKey = regKeyComponent.createInstance(nsIWindowsRegKey); + + // If it's already present because a previous test crashed or didn't clean up properly, clean it up first. + let keyName = BASE_PATH + "\\" + TESTDATA_KEYNAME; + setup_test_run(testKey, keyName); + + //* test that the write* functions write stuff + test_writing_functions(testKey); + + //* check that the valueCount/getValueName functions work for the values we just wrote + test_value_functions(testKey); + + //* check that the get* functions work for the values we just wrote. + test_reading_functions(testKey); + + //* check that the get* functions fail with the right exception codes if we ask for the wrong type or if the value name doesn't exist at all + test_invalidread_functions(testKey); + + //* check that creating/enumerating/deleting child keys works + test_childkey_functions(testKey); + + test_watching_functions(testKey); + + //* clean up + cleanup_test_run(testKey, keyName); +} + +function setup_test_run(testKey, keyName) +{ + do_print("Setup test run"); + try { + testKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_READ); + do_print("Test key exists. Needs cleanup."); + cleanup_test_run(testKey, keyName); + } + catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) + { + } + + testKey.create(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, keyName, nsIWindowsRegKey.ACCESS_ALL); +} + +function test_writing_functions(testKey) +{ + strictEqual(testKey.valueCount, 0); + + strictEqual(testKey.hasValue(TESTDATA_STRNAME), false); + testKey.writeStringValue(TESTDATA_STRNAME, TESTDATA_STRVALUE); + strictEqual(testKey.hasValue(TESTDATA_STRNAME), true); + + strictEqual(testKey.hasValue(TESTDATA_INTNAME), false); + testKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE); + + strictEqual(testKey.hasValue(TESTDATA_INT64NAME), false); + testKey.writeInt64Value(TESTDATA_INT64NAME, TESTDATA_INT64VALUE); + + strictEqual(testKey.hasValue(TESTDATA_BINARYNAME), false); + testKey.writeBinaryValue(TESTDATA_BINARYNAME, TESTDATA_BINARYVALUE); +} + +function test_value_functions(testKey) +{ + strictEqual(testKey.valueCount, 4); + strictEqual(testKey.getValueName(0), TESTDATA_STRNAME); + strictEqual(testKey.getValueName(1), TESTDATA_INTNAME); + strictEqual(testKey.getValueName(2), TESTDATA_INT64NAME); + strictEqual(testKey.getValueName(3), TESTDATA_BINARYNAME); +} + +function test_reading_functions(testKey) +{ + strictEqual(testKey.getValueType(TESTDATA_STRNAME), nsIWindowsRegKey.TYPE_STRING); + strictEqual(testKey.readStringValue(TESTDATA_STRNAME), TESTDATA_STRVALUE); + + strictEqual(testKey.getValueType(TESTDATA_INTNAME), nsIWindowsRegKey.TYPE_INT); + strictEqual(testKey.readIntValue(TESTDATA_INTNAME), TESTDATA_INTVALUE); + + strictEqual(testKey.getValueType(TESTDATA_INT64NAME), nsIWindowsRegKey.TYPE_INT64); + strictEqual( testKey.readInt64Value(TESTDATA_INT64NAME), TESTDATA_INT64VALUE); + + strictEqual(testKey.getValueType(TESTDATA_BINARYNAME), nsIWindowsRegKey.TYPE_BINARY); + strictEqual( testKey.readBinaryValue(TESTDATA_BINARYNAME), TESTDATA_BINARYVALUE); +} + +function test_invalidread_functions(testKey) +{ + try { + testKey.readIntValue(TESTDATA_STRNAME); + do_throw("Reading an integer from a string registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + let val = testKey.readStringValue(TESTDATA_INTNAME); + do_throw("Reading an string from an Int registry value should throw." + val); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + testKey.readStringValue(TESTDATA_INT64NAME); + do_throw("Reading an string from an Int64 registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + + try { + testKey.readStringValue(TESTDATA_BINARYNAME); + do_throw("Reading a string from an Binary registry value should throw."); + } catch (e if (e instanceof Ci.nsIException && e.result == Cr.NS_ERROR_FAILURE)) { + } + +} + +function test_childkey_functions(testKey) +{ + strictEqual(testKey.childCount, 0); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false); + + let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + childKey.close(); + + strictEqual(testKey.childCount, 1); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), true); + strictEqual(testKey.getChildName(0), TESTDATA_CHILD_KEY); + + childKey = testKey.openChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + testKey.removeChild(TESTDATA_CHILD_KEY); + strictEqual(testKey.childCount, 0); + strictEqual(testKey.hasChild(TESTDATA_CHILD_KEY), false); +} + +function test_watching_functions(testKey) +{ + strictEqual(testKey.isWatching(), false); + strictEqual(testKey.hasChanged(), false); + + testKey.startWatching(true); + strictEqual(testKey.isWatching(), true); + + testKey.stopWatching(); + strictEqual(testKey.isWatching(), false); + + // Create a child key, and update a value + let childKey = testKey.createChild(TESTDATA_CHILD_KEY, nsIWindowsRegKey.ACCESS_ALL); + childKey.writeIntValue(TESTDATA_INTNAME, TESTDATA_INTVALUE); + + // Start a recursive watch, and update the child's value + testKey.startWatching(true); + strictEqual(testKey.isWatching(), true); + + childKey.writeIntValue(TESTDATA_INTNAME, 0); + strictEqual(testKey.hasChanged(), true); + testKey.stopWatching(); + strictEqual(testKey.isWatching(), false); + + childKey.removeValue(TESTDATA_INTNAME); + childKey.close(); + testKey.removeChild(TESTDATA_CHILD_KEY); +} + +function cleanup_test_run(testKey, keyName) +{ + do_print("Cleaning up test."); + + for (var i = 0; i < testKey.childCount; i++) { + testKey.removeChild(testKey.getChildName(i)); + } + testKey.close(); + + let baseKey = regKeyComponent.createInstance(nsIWindowsRegKey); + baseKey.open(nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, BASE_PATH, nsIWindowsRegKey.ACCESS_ALL); + baseKey.removeChild(TESTDATA_KEYNAME); + baseKey.close(); +} + +// Test data used above. +const BASE_PATH = "SOFTWARE"; +const TESTDATA_KEYNAME = "TestRegXPC"; +const TESTDATA_STRNAME = "AString"; +const TESTDATA_STRVALUE = "The quick brown fox jumps over the lazy dog."; +const TESTDATA_INTNAME = "AnInteger"; +const TESTDATA_INTVALUE = 65536; +const TESTDATA_INT64NAME = "AnInt64"; +const TESTDATA_INT64VALUE = 9223372036854775807; +const TESTDATA_BINARYNAME = "ABinary"; +const TESTDATA_BINARYVALUE = "She sells seashells by the seashore"; +const TESTDATA_CHILD_KEY = "TestChildKey"; diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini index 371b8a846a..6b75a1b710 100644 --- a/xpcom/tests/unit/xpcshell.ini +++ b/xpcom/tests/unit/xpcshell.ini @@ -77,3 +77,5 @@ skip-if = os == "win" fail-if = os == "android" [test_file_renameTo.js] [test_notxpcom_scriptable.js] +[test_windows_registry.js] +skip-if = os != "win"