mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
import change from rmottola/Arctic-Fox:
- Add legacycollector.org to add-ons whitelist (dc69faacb) - Bug 1112469 - Part 1: Implement an XPCOM service responsible to trigger daily updates of service workers; r=nsm (74f735500) - Bug 1133601 - Implement about:serviceworkers, r=ehsan (e21767ec1) - Bug 1038811 - Push Notifications - Move old push to simplepush. (14b0a1547) - Bug 1041339 - ServiceWorkers: Update implementation based on clarification of force-refresh. r=nsm (484675660) - Bug 1154547 - Part 1: Linkify the worker script URLs in about:serviceworkers; r=baku (db2097fa7) - Bug 1154547 - Part 2: Make it possible to update a service worker from about:serviceworkers; r=baku (03d7363aa) - Bug 1154721 - Add an Unregister button to about:serviceworkers, r=ehsan (7b5a9873f) - Bug 1156052 - Add push information to about:serviceworkers. r=baku (995f5b1d3) - Bug 1158811 - remove the flickering in about:serviceworkers, r=ehsan (70a4cb1bc) - Bug 1158361 - Improve the localized messages in about:serviceworkers, r=ehsan, f=stef (751202c01) - Bug 1151664 - Make claim return undefined for now. r=nsm (84f36584b) - Bug 1142693 - Recognize EMSGSIZE as non-fatal on OS X for IPC sendmsg(). r=bent (c133bb505) - Bug 1150916 - Non-unified bustage follow-up fix. (19adaff8b) - Bug 1151607 - Step 1: Add Linux sandboxing hook for when child processes are still single-threaded. r=kang r=bent (e5e67f4b1) - Bug 1151607 - Step 1.5: Avoid unlikely false positives in Linux SandboxInfo feature detection. r=kang (944805781) - Bug 1151607 - Step 2: Apply net/ipc namespace separation and chroot to media plugins. r=kang (3dc0e575f) - Bug 1151607 - Step 0: sort includes to make the following patches cleaner. r=kang (9b918989b) - Bug 1038811 - Push Notifications - Firefox front end changes for preferences, and permission notification. r=MattN+bmo@mozilla.com (fdb4c7636) - (adapted) Bug 1147281 - Shared browser notification icon CSS. r=MattN (2243c83a1) - Bug 1123523 - Part 1: Add an nsIAnimationObserver interface to watch adding/changing/removing AnimationPlayer objects. r=smaug (d889e512c) - Bug 1123523 - Part 2: Add an animations option for MutationObservers and expose chrome-only animation members on MutationRecords. r=smaug (6c9622c0f) - Bug 1123523 - Part 3: Store a flag on AnimationPlayer for whether it is exposed by Element.getAnimationPlayers(). r=birtles (d146779c0) - Bug 1123523 - Part 4: Add macro for notifying observers only when they implement a specific derived interface. r=smaug (38714002f) - Bug 1123523 - Part 5: Record on a document whether it might have any nsIAnimationObservers registered. r=smaug (585e30299) - Bug 1123523 - Part 6: Listen for nsIAnimationObserver notifications and translate them to MutationObserver notifications. r=smaug (9980c91e5) - Bug 1123523 - Part 7: Add utility functions to notify registered nsIAnimationObservers. r=smaug (82d3a15cf) - Bug 1123523 - Part 8: Dispatch nsIAnimationObserver notifications when an animation is added or removed. r=birtles (056b8bf7a) - Bug 1123523 - Part 9: Dispatch an nsIAnimationObserver notification when an animation is changed. r=birtles (5787cdbc1) - Bug 1123523 - Part 10: Tests. r=birtles (d134aa3b0) - Bug 1123523 - Followup build fix. (b88bae25d) - Bug 1137515 part 1 - Change to configure.in r=mwu (150534251) - Bug 1136065 - Remove GetRangeCount() in Selection.h. r=ehsan (bd35dba49) - Bug 1129249 - Expose the element id in Gecko profiler for Restyle. r=dholbert r=benwa (77231d128) - Bug 979293 - Add a FrozenAtomSet to clarify how |permanentAtoms| works. r=bhackett. (1c4ca9315) - Bug 979293 - Don't write collision bits in HashTable unnecessarily. r=luke. (c42ebc7b5) - Bug 1135200: Hook up nsCSSParser's pref-backed bool variables in a startup method. r=heycam (e129dcfc8) - Bug 1107378 - Part 1: Create a JS-implemented "CSS Unprefixing Service" that can convert certain -webkit prefixed CSS to an unprefixed form. r=dbaron (c860167d2) - Bug 1107378 - Part 2: Make the CSS Parser call out to the unprefixing service, when it detects a vendor-prefixed property name (if pref is enabled). r=dbaron (1fe4e48dd) - Bug 1107378 - Part 3: In cases where we're unprefixing, treat "display:-webkit-box" as "display: flex" (& same for "-moz-box" if we previously saw "-webkit-box"). r=dbaron (00299fb08) - Bug 1107378 - Part 4: Add mochitest for our CSS unprefixing functionality. r=dbaron (95a0e6c41) - Bug 1132743: Only allow CSS Unprefixing Service to be activated for hosts on a small, hardcoded whitelist. r=dbaron f=bz (6afd0dd07) - Bug 1132743 followup: hook up nsPrincipal.cpp's gCodeBasePrincipalSupport in new InitializeStatics method, instead of lazily. implicit rs=dbaron (7223553f1) - Bug 1124503 move AppConstants.jsm to toolkit r=gavin (0a90334ff) - Bug 1130195: Report the failed bitmap creation, but still crash. (9e8c8fcde) - Bug 1136241 - making sure that hint/role strings are returned with no spaces to support localization. r=eeejay (665243ab4) - Bug 1127084 - Remove __iterator__ from ContentPrefStore. (126621dbf) - Bug 1133449 - [B2G] The default audio type didn't be set correctly when the call screen app is launched. r=baku (0470b702a) - Bug 1133449 - [B2G] The default audio type didn't be set correctly when the call screen app is launched. r=baku (016b84983) - Bug 1130175 - nICEr: avoid sysctl.h include. r=bwc (5446f87d1) - Bug 794984 - [mozprocess] Add ability to separate stderr from stdout. r=ahal (9388e0e08) - Bug 1136803 - Properly remove the force-dtc override flag on retained layers when listeners are removed. r=botond (1047b11a7) - Bug 1134493 - Ensure we don't set the force-empty-hit-region flag when a subdocument has mozpasspointerevents. r=botond (fda5e8176) - Bug 1136487: Destroy the compositors for all windows when any window detects a device reset. r=jrmuizel (22d45787c) - bits of Bug 1135773 - Initialize QI return values to null in the cycle collector. (rest was already part of 1119482 (6f30ef196) - Bug 1135772 - Return null on failure in nsXPCWrappedJS's QueryInterface. r=smaug (67fca5218) - Bug 1136584 - Copy JIT options from global settings. r=bhackett (6696b345e) - Bug 1135912 - Don't repaint vibrant regions on mouseover. (1de120955) - Bug 961887 - Refactor mVisibleAboveRegion management. r=roc (8281fb9f8) - Bug 961887 - Make FindOpaqueBackgroundColorFor take a region instead of a PaintedLayerData. r=roc (f42ddc1a1) - Bug 961887 - Find uniform opaque background colors under ContainerLayers. r=roc (7378892b8)
This commit is contained in:
@@ -139,7 +139,7 @@ AccTextSelChangeEvent::~AccTextSelChangeEvent() { }
|
||||
bool
|
||||
AccTextSelChangeEvent::IsCaretMoveOnly() const
|
||||
{
|
||||
return mSel->GetRangeCount() == 1 && mSel->IsCollapsed() &&
|
||||
return mSel->RangeCount() == 1 && mSel->IsCollapsed() &&
|
||||
((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
|
||||
nsISelectionListener::COLLAPSETOEND_REASON)) == 0);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ HyperTextAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
|
||||
{
|
||||
dom::Selection* domSel = DOMSelection();
|
||||
return domSel &&
|
||||
SetSelectionBoundsAt(domSel->GetRangeCount(), aStartOffset, aEndOffset);
|
||||
SetSelectionBoundsAt(domSel->RangeCount(), aStartOffset, aEndOffset);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
||||
@@ -1137,7 +1137,7 @@ HyperTextAccessible::SetSelectionRange(int32_t aStartPos, int32_t aEndPos)
|
||||
NS_ENSURE_STATE(domSel);
|
||||
|
||||
// Set up the selection.
|
||||
for (int32_t idx = domSel->GetRangeCount() - 1; idx > 0; idx--)
|
||||
for (int32_t idx = domSel->RangeCount() - 1; idx > 0; idx--)
|
||||
domSel->RemoveRange(domSel->GetRangeAt(idx));
|
||||
SetSelectionBoundsAt(0, aStartPos, aEndPos);
|
||||
|
||||
@@ -1442,7 +1442,7 @@ HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
|
||||
return false;
|
||||
|
||||
nsRefPtr<nsRange> range;
|
||||
uint32_t rangeCount = domSel->GetRangeCount();
|
||||
uint32_t rangeCount = domSel->RangeCount();
|
||||
if (aSelectionNum == static_cast<int32_t>(rangeCount))
|
||||
range = new nsRange(mContent);
|
||||
else
|
||||
@@ -1470,7 +1470,7 @@ HyperTextAccessible::RemoveFromSelection(int32_t aSelectionNum)
|
||||
if (!domSel)
|
||||
return false;
|
||||
|
||||
if (aSelectionNum < 0 || aSelectionNum >= domSel->GetRangeCount())
|
||||
if (aSelectionNum < 0 || aSelectionNum >= static_cast<int32_t>(domSel->RangeCount()))
|
||||
return false;
|
||||
|
||||
domSel->RemoveRange(domSel->GetRangeAt(aSelectionNum));
|
||||
@@ -1901,7 +1901,7 @@ HyperTextAccessible::GetSpellTextAttr(nsINode* aNode,
|
||||
if (!domSel)
|
||||
return;
|
||||
|
||||
int32_t rangeCount = domSel->GetRangeCount();
|
||||
int32_t rangeCount = domSel->RangeCount();
|
||||
if (rangeCount <= 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ let OutputGenerator = {
|
||||
},
|
||||
|
||||
_getOutputName: function _getOutputName(aName) {
|
||||
return aName.replace(' ', '');
|
||||
return aName.replace(/\s/g, '');
|
||||
},
|
||||
|
||||
roleRuleMap: {
|
||||
|
||||
@@ -848,7 +848,8 @@ PivotContext.prototype = {
|
||||
hints.push(hint);
|
||||
} else if (aAccessible.actionCount > 0) {
|
||||
hints.push({
|
||||
string: Utils.AccRetrieval.getStringRole(aAccessible.role) + '-hint'
|
||||
string: Utils.AccRetrieval.getStringRole(
|
||||
aAccessible.role).replace(/\s/g, '') + '-hint'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
accOrElmOrID: 'nested_link3',
|
||||
expectedHints: [{string: 'link-hint'}, {string: 'pushbutton-hint'},
|
||||
"Double tap and hold to activate"]
|
||||
}, {
|
||||
accOrElmOrID: 'menuitemradio',
|
||||
expectedHints: [{string: 'radiomenuitem-hint'}]
|
||||
}];
|
||||
|
||||
// Test hints.
|
||||
@@ -80,6 +83,7 @@
|
||||
<a href="#" id="link_with_hint_override" aria-moz-hint="Tap and hold to get to menu">I am a special link</a>
|
||||
<button id="button_with_default_hint">Toggle</button>
|
||||
<button id="button_with_hint_override" aria-moz-hint="Tap and hold to activate">Special</button>
|
||||
<span id="menuitemradio" role="menuitemradio">Item 1</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -50,6 +50,7 @@ MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
|
||||
|
||||
MOZ_TIME_MANAGER=1
|
||||
|
||||
MOZ_SIMPLEPUSH=1
|
||||
MOZ_PAY=1
|
||||
MOZ_TOOLKIT_SEARCH=
|
||||
MOZ_PLACES=
|
||||
|
||||
@@ -537,6 +537,8 @@
|
||||
@BINPATH@/components/formautofill.manifest
|
||||
@BINPATH@/components/FormAutofillContentService.js
|
||||
@BINPATH@/components/FormAutofillStartup.js
|
||||
@BINPATH@/components/CSSUnprefixingService.js
|
||||
@BINPATH@/components/CSSUnprefixingService.manifest
|
||||
@BINPATH@/components/contentAreaDropListener.manifest
|
||||
@BINPATH@/components/contentAreaDropListener.js
|
||||
@BINPATH@/components/messageWakeupService.js
|
||||
|
||||
@@ -201,7 +201,7 @@ pref("extensions.dss.switchPending", false); // Non-dynamic switch pending af
|
||||
pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.name", "chrome://browser/locale/browser.properties");
|
||||
pref("extensions.{972ce4c6-7e08-4474-a285-3208198ce6fd}.description", "chrome://browser/locale/browser.properties");
|
||||
|
||||
pref("xpinstall.whitelist.add", "addons.mozilla.org,www.palemoon.org,addons.palemoon.org");
|
||||
pref("xpinstall.whitelist.add", "addons.mozilla.org,www.palemoon.org,addons.palemoon.org,legacycollector.org");
|
||||
pref("xpinstall.whitelist.add.36", "");
|
||||
pref("xpinstall.whitelist.add.180", "");
|
||||
pref("xpinstall.whitelist.required", false);
|
||||
@@ -756,6 +756,7 @@ pref("goanna.handlerService.allowRegisterFromDifferentHost", false);
|
||||
|
||||
pref("browser.geolocation.warning.infoURL", "http://www.palemoon.org/info-url/geolocation.shtml");
|
||||
pref("browser.mixedcontent.warning.infoURL", "http://www.palemoon.org/info-url/mixedcontent.shtml");
|
||||
pref("browser.push.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/push/");
|
||||
|
||||
pref("browser.EULA.version", 3);
|
||||
pref("browser.rights.version", 3);
|
||||
|
||||
@@ -431,6 +431,7 @@
|
||||
<box id="notification-popup-box" hidden="true" align="center">
|
||||
<image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="push-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
<image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
|
||||
|
||||
@@ -1773,6 +1773,42 @@ ContentPermissionPrompt.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_promptPush : function(aRequest) {
|
||||
var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
var requestingURI = aRequest.principal.URI;
|
||||
|
||||
var message = browserBundle.formatStringFromName("push.enablePush",
|
||||
[requestingURI.host], 1);
|
||||
|
||||
var actions = [
|
||||
{
|
||||
stringId: "push.alwaysAllow",
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {}
|
||||
},
|
||||
{
|
||||
stringId: "push.allowForSession",
|
||||
action: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
expireType: Ci.nsIPermissionManager.EXPIRE_SESSION,
|
||||
callback: function() {}
|
||||
},
|
||||
{
|
||||
stringId: "push.alwaysBlock",
|
||||
action: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
expireType: null,
|
||||
callback: function() {}
|
||||
}]
|
||||
|
||||
var options = {
|
||||
learnMoreURL: Services.urlFormatter.formatURLPref("browser.push.warning.infoURL"),
|
||||
};
|
||||
|
||||
this._showPrompt(aRequest, message, "push", actions, "push",
|
||||
"push-notification-icon", options);
|
||||
|
||||
},
|
||||
|
||||
_promptGeo : function(aRequest) {
|
||||
var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
var requestingURI = aRequest.principal.URI;
|
||||
@@ -1897,7 +1933,6 @@ ContentPermissionPrompt.prototype = {
|
||||
},
|
||||
|
||||
prompt: function CPP_prompt(request) {
|
||||
|
||||
// Only allow exactly one permission rquest here.
|
||||
let types = request.types.QueryInterface(Ci.nsIArray);
|
||||
if (types.length != 1) {
|
||||
@@ -1909,6 +1944,7 @@ ContentPermissionPrompt.prototype = {
|
||||
const kFeatureKeys = { "geolocation" : "geo",
|
||||
"desktop-notification" : "desktop-notification",
|
||||
"pointerLock" : "pointerLock",
|
||||
"push" : "push"
|
||||
};
|
||||
|
||||
// Make sure that we support the request.
|
||||
@@ -1952,6 +1988,9 @@ ContentPermissionPrompt.prototype = {
|
||||
case "pointerLock":
|
||||
this._promptPointerLock(request, autoAllow);
|
||||
break;
|
||||
case "push":
|
||||
this._promptPush(request);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -483,12 +483,12 @@ let AboutPermissions = {
|
||||
*/
|
||||
_supportedPermissions: ["password", "image", "popup", "cookie",
|
||||
"desktop-notification", "install", "geo", "indexedDB",
|
||||
"fullscreen", "pointerLock"],
|
||||
"fullscreen", "push", "pointerLock"],
|
||||
|
||||
/**
|
||||
* Permissions that don't have a global "Allow" option.
|
||||
*/
|
||||
_noGlobalAllow: ["desktop-notification", "geo", "indexedDB", "fullscreen",
|
||||
_noGlobalAllow: ["desktop-notification", "geo", "indexedDB", "fullscreen", "push"
|
||||
"pointerLock"],
|
||||
|
||||
/**
|
||||
@@ -537,6 +537,7 @@ let AboutPermissions = {
|
||||
Services.prefs.addObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.addObserver("plugins.click_to_play", this, false);
|
||||
Services.prefs.addObserver("full-screen-api.enabled", this, false);
|
||||
Services.prefs.addObserver("dom.push.enabled", this, false);
|
||||
Services.prefs.addObserver("full-screen-api.pointer-lock.enabled", this, false);
|
||||
Services.prefs.addObserver("permissions.places-sites-limit", this, false);
|
||||
|
||||
@@ -689,6 +690,7 @@ let AboutPermissions = {
|
||||
Services.prefs.removeObserver("dom.indexedDB.enabled", this, false);
|
||||
Services.prefs.removeObserver("plugins.click_to_play", this, false);
|
||||
Services.prefs.removeObserver("full-screen-api.enabled", this, false);
|
||||
Services.prefs.removeObserver("dom.push.enabled", this, false);
|
||||
Services.prefs.removeObserver("full-screen-api.pointer-lock.enabled", this, false);
|
||||
Services.prefs.removeObserver("permissions.places-sites-limit", this, false);
|
||||
|
||||
|
||||
@@ -360,7 +360,28 @@
|
||||
oncommand="AboutPermissions.onPermissionCommand(event, true);"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
<!-- Push Notifications -->
|
||||
<hbox id="push-pref-item"
|
||||
class="pref-item" align="top">
|
||||
<image class="pref-icon" type="push"/>
|
||||
<vbox>
|
||||
<label class="pref-title" value="&push.label;"/>
|
||||
<hbox align="center">
|
||||
<menulist id="push-menulist"
|
||||
class="pref-menulist"
|
||||
type="push"
|
||||
oncommand="AboutPermissions.onPermissionCommand(event);">
|
||||
<menupopup>
|
||||
<menuitem id="push-0" value="0" label="&permission.alwaysAsk;"/>
|
||||
<menuitem id="push-1" value="1" label="&permission.allow;"/>
|
||||
<menuitem id="push-2" value="2" label="&permission.block;"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<!-- PointerLock -->
|
||||
<hbox id="pointerLock-pref-item"
|
||||
|
||||
@@ -491,6 +491,8 @@
|
||||
@RESPATH@/components/formautofill.manifest
|
||||
@RESPATH@/components/FormAutofillContentService.js
|
||||
@RESPATH@/components/FormAutofillStartup.js
|
||||
@RESPATH@/components/CSSUnprefixingService.js
|
||||
@RESPATH@/components/CSSUnprefixingService.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.manifest
|
||||
@RESPATH@/components/contentAreaDropListener.js
|
||||
@RESPATH@/browser/components/BrowserProfileMigrators.manifest
|
||||
|
||||
@@ -305,6 +305,15 @@ webNotifications.neverShow=Always Block Notifications
|
||||
webNotifications.neverShow.accesskey=N
|
||||
webNotifications.showFromSite=Would you like to show notifications from %S?
|
||||
|
||||
# Push Notifications
|
||||
push.allowForSession=Allow for Session
|
||||
push.allowForSession.accesskey=S
|
||||
push.alwaysAllow=Always Allow Push Notifications
|
||||
push.alwaysAllow.accesskey=A
|
||||
push.alwaysBlock=Always Block Push Notifications
|
||||
push.alwaysBlock.accesskey=B
|
||||
push.enablePush=Would you like to allow Push Notifications for %S?
|
||||
|
||||
# Pointer lock UI
|
||||
|
||||
pointerLock.allow2=Hide pointer
|
||||
|
||||
@@ -53,4 +53,6 @@
|
||||
|
||||
<!ENTITY fullscreen.label "Fullscreen">
|
||||
|
||||
<!ENTITY push.label "Receive Push Notifications">
|
||||
|
||||
<!ENTITY pointerLock.label "Hide the Mouse Pointer">
|
||||
|
||||
@@ -1153,35 +1153,7 @@ toolbar[iconsize="small"] #webrtc-status-button {
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-cancelled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-origin-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
.addon-progress-description {
|
||||
width: 350px;
|
||||
@@ -1206,66 +1178,13 @@ toolbar[iconsize="small"] #webrtc-status-button {
|
||||
list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password-save"],
|
||||
.popup-notification-icon[popupid="password-change"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://browser/skin/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="mixed-content-blocked"] {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 4px;
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
margin-top: -1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
outline: 1px dotted -moz-DialogText;
|
||||
}
|
||||
@@ -1275,101 +1194,13 @@ toolbar[iconsize="small"] #webrtc-status-button {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#alert-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon,
|
||||
#alert-plugins-notification-icon,
|
||||
#blocked-plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover,
|
||||
#alert-plugins-notification-icon:hover,
|
||||
#blocked-plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active,
|
||||
#alert-plugins-notification-icon:active,
|
||||
#blocked-plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mixed-content-blocked-notification-icon,
|
||||
#mixed-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
#pointerLock-cancel {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ browser.jar:
|
||||
* skin/classic/browser/engineManager.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/Go-arrow.png
|
||||
skin/classic/browser/identity.png
|
||||
skin/classic/browser/imagedocument.png
|
||||
|
||||
@@ -98,6 +98,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
@@ -1872,27 +1872,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-cancelled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-origin-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
@@ -1935,61 +1914,11 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password-save"],
|
||||
.popup-notification-icon[popupid="password-change"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://browser/skin/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="mixed-content-blocked"] {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-radius: 2.5px 0 0 2.5px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
@@ -1997,44 +1926,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#alert-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon,
|
||||
#alert-plugins-notification-icon,
|
||||
@@ -2054,45 +1946,11 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mixed-content-blocked-notification-icon,
|
||||
#mixed-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
|
||||
@@ -23,6 +23,10 @@ browser.jar:
|
||||
* skin/classic/browser/engineManager.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-16@2x.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/Push-64@2x.png
|
||||
skin/classic/browser/Info.png
|
||||
skin/classic/browser/identity.png
|
||||
skin/classic/browser/imagedocument.png
|
||||
|
||||
@@ -101,6 +101,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
%if 0
|
||||
/* 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/. */
|
||||
%endif
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-confirmation"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install-progress"],
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.identity-notification-icon,
|
||||
#identity-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/profile/profileicon.png);
|
||||
/* XXX: need HiDPI version */
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#push-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Push-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bad-content-blocked-notification-icon,
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.bad-content-unblocked-notification-icon,
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 16px, 16px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16.png);
|
||||
-moz-image-region: rect(0px, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64.png);
|
||||
}
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16.png);
|
||||
}
|
||||
|
||||
/* EME notifications */
|
||||
|
||||
.popup-notification-icon[popupid="drmContentPlaying"],
|
||||
#eme-notification-icon {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
|
||||
}
|
||||
|
||||
#eme-notification-icon:hover:active {
|
||||
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
|
||||
}
|
||||
|
||||
#eme-notification-icon[firstplay=true] {
|
||||
animation: emeTeachingMoment 0.2s linear 0s 5 normal;
|
||||
}
|
||||
|
||||
@keyframes emeTeachingMoment {
|
||||
0% {transform: translateX(0); }
|
||||
25% {transform: translateX(3px) }
|
||||
75% {transform: translateX(-3px) }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
%ifdef XP_MACOSX
|
||||
/* HiDPI notification icons */
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#notification-popup-box {
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-32.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16@2x.png);
|
||||
}
|
||||
|
||||
#push-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Push-16@2x.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-32.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16@2x.png);
|
||||
}
|
||||
|
||||
.webapps-notification-icon,
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/webapps-16@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-hidden {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon.plugin-blocked {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked@2x.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 96px, 32px, 64px);
|
||||
}
|
||||
|
||||
#bad-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
|
||||
}
|
||||
|
||||
#bad-content-unblocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareMicrophone-notification-icon,
|
||||
#webRTC-shareMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingMicrophone-notification-icon,
|
||||
#webRTC-sharingMicrophone-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingMicrophone-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-shareScreen-notification-icon,
|
||||
#webRTC-shareScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-16@2x.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingScreen-notification-icon,
|
||||
#webRTC-sharingScreen-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingScreen-16@2x.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16@2x.png);
|
||||
}
|
||||
|
||||
.pointerLock-notification-icon,
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
|
||||
}
|
||||
|
||||
.translate-notification-icon,
|
||||
#translate-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 32px, 32px, 0px);
|
||||
}
|
||||
|
||||
.translated-notification-icon,
|
||||
#translated-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/translation-16@2x.png);
|
||||
-moz-image-region: rect(0px, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
|
||||
.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
|
||||
list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingMicrophone"],
|
||||
.popup-notification-icon[popupid="webRTC-shareMicrophone"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingScreen"],
|
||||
.popup-notification-icon[popupid="webRTC-shareScreen"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareScreen-64@2x.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="servicesInstall"] {
|
||||
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
|
||||
}
|
||||
|
||||
#servicesInstall-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
|
||||
}
|
||||
}
|
||||
%endif
|
||||
@@ -2362,35 +2362,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
.popup-notification-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
-moz-margin-end: 10px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||
.popup-notification-icon[popupid="addon-progress"],
|
||||
.popup-notification-icon[popupid="addon-install-cancelled"],
|
||||
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-origin-blocked"],
|
||||
.popup-notification-icon[popupid="addon-install-failed"],
|
||||
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="click-to-play-plugins"] {
|
||||
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="web-notifications"] {
|
||||
list-style-image: url(chrome://browser/skin/notification-64.png);
|
||||
}
|
||||
%include ../shared/notification-icons.inc.css
|
||||
|
||||
.addon-progress-description {
|
||||
width: 350px;
|
||||
@@ -2423,61 +2395,9 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
-moz-image-region: rect(32px, 32px, 48px, 16px);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
|
||||
.popup-notification-icon[popupid="indexedDB-quota-prompt"],
|
||||
.popup-notification-icon[popupid*="offline-app-requested"],
|
||||
.popup-notification-icon[popupid="offline-app-usage"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="password-save"],
|
||||
.popup-notification-icon[popupid="password-change"] {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webapps-install"] {
|
||||
list-style-image: url(chrome://browser/skin/webapps-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="mixed-content-blocked"] {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="webRTC-sharingDevices"],
|
||||
.popup-notification-icon[popupid="webRTC-shareDevices"] {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="pointerLock"] {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-64.png);
|
||||
}
|
||||
|
||||
/* Notification icon box */
|
||||
#notification-popup-box {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
padding-left: 3px;
|
||||
border-radius: var(--toolbarbutton-border-radius) 0 0 var(--toolbarbutton-border-radius);
|
||||
border-width: 0 8px 0 0;
|
||||
border-style: solid;
|
||||
border-image: url("chrome://browser/skin/urlbar-arrow.png") 0 8 0 0 fill;
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
.notification-anchor-icon:-moz-locale-dir(rtl) {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.notification-anchor-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.notification-anchor-icon:-moz-focusring {
|
||||
@@ -2485,106 +2405,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
.default-notification-icon,
|
||||
#default-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/information-16.png);
|
||||
}
|
||||
|
||||
.geo-notification-icon,
|
||||
#geo-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-16.png);
|
||||
}
|
||||
|
||||
#addons-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||
}
|
||||
|
||||
.indexedDB-notification-icon,
|
||||
#indexedDB-notification-icon {
|
||||
list-style-image: url(chrome://global/skin/icons/question-16.png);
|
||||
}
|
||||
|
||||
#password-notification-icon {
|
||||
list-style-image: url(chrome://mozapps/skin/passwordmgr/key-16.png);
|
||||
}
|
||||
|
||||
#webapps-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webapps-16.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginNormal.png);
|
||||
}
|
||||
|
||||
#alert-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginAlert.png);
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-pluginBlocked.png);
|
||||
}
|
||||
|
||||
#plugins-notification-icon,
|
||||
#alert-plugins-notification-icon,
|
||||
#blocked-plugins-notification-icon {
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:hover,
|
||||
#alert-plugins-notification-icon:hover,
|
||||
#blocked-plugins-notification-icon:hover {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
#plugins-notification-icon:active,
|
||||
#alert-plugins-notification-icon:active,
|
||||
#blocked-plugins-notification-icon:active {
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
}
|
||||
|
||||
#notification-popup-box[hidden] {
|
||||
/* Override display:none to make the pluginBlockedNotification animation work
|
||||
when showing the notification repeatedly. */
|
||||
display: -moz-box;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#blocked-plugins-notification-icon[showing] {
|
||||
animation: pluginBlockedNotification 500ms ease 0s 5 alternate both;
|
||||
}
|
||||
|
||||
@keyframes pluginBlockedNotification {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.mixed-content-blocked-notification-icon,
|
||||
#mixed-content-blocked-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/mixed-content-blocked-16.png);
|
||||
}
|
||||
|
||||
.webRTC-shareDevices-notification-icon,
|
||||
#webRTC-shareDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
|
||||
}
|
||||
|
||||
.webRTC-sharingDevices-notification-icon,
|
||||
#webRTC-sharingDevices-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
|
||||
}
|
||||
|
||||
.web-notifications-notification-icon,
|
||||
#web-notifications-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/notification-16.png);
|
||||
}
|
||||
|
||||
#pointerLock-notification-icon {
|
||||
list-style-image: url(chrome://browser/skin/pointerLock-16.png);
|
||||
}
|
||||
#pointerLock-cancel {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ browser.jar:
|
||||
* skin/classic/browser/engineManager.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Push-16.png
|
||||
skin/classic/browser/Push-64.png
|
||||
skin/classic/browser/Info.png
|
||||
skin/classic/browser/identity.png
|
||||
skin/classic/browser/imagedocument.png
|
||||
|
||||
@@ -101,6 +101,9 @@
|
||||
.pref-icon[type="geo"] {
|
||||
list-style-image: url(chrome://browser/skin/Geolocation-64.png);
|
||||
}
|
||||
.pref-icon[type="push"] {
|
||||
list-style-image: url(chrome://browser/skin/Push-64.png);
|
||||
}
|
||||
.pref-icon[type="indexedDB"] {
|
||||
list-style-image: url(chrome://global/skin/icons/question-48.png);
|
||||
}
|
||||
|
||||
+10
-1
@@ -20,7 +20,7 @@ interface nsIContentSecurityPolicy;
|
||||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
|
||||
[scriptable, builtinclass, uuid(204555e7-04ad-4cc8-9f0e-840615cc43e8)]
|
||||
[scriptable, builtinclass, uuid(264fe8ca-c382-11e4-95a6-782bcbaebb28)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
@@ -230,6 +230,15 @@ interface nsIPrincipal : nsISerializable
|
||||
* unknown, hence assumed minimally privileged, security context).
|
||||
*/
|
||||
[infallible] readonly attribute boolean isNullPrincipal;
|
||||
|
||||
/**
|
||||
* Returns true if this principal's origin is recognized as being on the
|
||||
* whitelist of sites that can use the CSS Unprefixing Service.
|
||||
*
|
||||
* (This interface provides a trivial implementation, just returning false;
|
||||
* subclasses can implement something more complex as-needed.)
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] bool IsOnCSSUnprefixingWhitelist();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -318,6 +318,12 @@ nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain)
|
||||
return mURI->GetPath(aBaseDomain);
|
||||
}
|
||||
|
||||
bool
|
||||
nsNullPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* nsISerializable implementation
|
||||
*/
|
||||
|
||||
+164
-10
@@ -14,12 +14,14 @@
|
||||
#include "pratom.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
@@ -31,8 +33,8 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static bool gIsWhitelistingTestDomains = false;
|
||||
static bool gCodeBasePrincipalSupport = false;
|
||||
static bool gIsObservingCodeBasePrincipalSupport = false;
|
||||
|
||||
static bool URIIsImmutable(nsIURI* aURI)
|
||||
{
|
||||
@@ -72,15 +74,6 @@ nsBasePrincipal::Release()
|
||||
|
||||
nsBasePrincipal::nsBasePrincipal()
|
||||
{
|
||||
if (!gIsObservingCodeBasePrincipalSupport) {
|
||||
nsresult rv =
|
||||
Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport,
|
||||
"signed.applets.codebase_principal_support",
|
||||
false);
|
||||
gIsObservingCodeBasePrincipalSupport = NS_SUCCEEDED(rv);
|
||||
NS_WARN_IF_FALSE(gIsObservingCodeBasePrincipalSupport,
|
||||
"Installing gCodeBasePrincipalSupport failed!");
|
||||
}
|
||||
}
|
||||
|
||||
nsBasePrincipal::~nsBasePrincipal(void)
|
||||
@@ -126,6 +119,19 @@ NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal,
|
||||
NS_IMPL_ADDREF_INHERITED(nsPrincipal, nsBasePrincipal)
|
||||
NS_IMPL_RELEASE_INHERITED(nsPrincipal, nsBasePrincipal)
|
||||
|
||||
// Called at startup:
|
||||
/* static */ void
|
||||
nsPrincipal::InitializeStatics()
|
||||
{
|
||||
Preferences::AddBoolVarCache(
|
||||
&gIsWhitelistingTestDomains,
|
||||
"layout.css.unprefixing-service.include-test-domains");
|
||||
|
||||
Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport,
|
||||
"signed.applets.codebase_principal_support",
|
||||
false);
|
||||
}
|
||||
|
||||
nsPrincipal::nsPrincipal()
|
||||
: mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
|
||||
, mInMozBrowser(false)
|
||||
@@ -608,6 +614,145 @@ nsPrincipal::GetAppStatus()
|
||||
return nsScriptSecurityManager::AppStatusForPrincipal(this);
|
||||
}
|
||||
|
||||
// Helper-function to indicate whether the CSS Unprefixing Service
|
||||
// whitelist should include dummy domains that are only intended for
|
||||
// use in testing. (Controlled by a pref.)
|
||||
static inline bool
|
||||
IsWhitelistingTestDomains()
|
||||
{
|
||||
return gIsWhitelistingTestDomains;
|
||||
}
|
||||
|
||||
// Checks if the given URI's host is on our "full domain" whitelist
|
||||
// (i.e. if it's an exact match against a domain that needs unprefixing)
|
||||
static bool
|
||||
IsOnFullDomainWhitelist(nsIURI* aURI)
|
||||
{
|
||||
nsAutoCString hostStr;
|
||||
nsresult rv = aURI->GetHost(hostStr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// NOTE: This static whitelist is expected to be short. If that changes,
|
||||
// we should consider a different representation; e.g. hash-set, prefix tree.
|
||||
static const nsLiteralCString sFullDomainsOnWhitelist[] = {
|
||||
// 0th entry only active when testing:
|
||||
NS_LITERAL_CSTRING("test1.example.org"),
|
||||
NS_LITERAL_CSTRING("map.baidu.com"),
|
||||
NS_LITERAL_CSTRING("music.baidu.com"),
|
||||
NS_LITERAL_CSTRING("3g.163.com"),
|
||||
NS_LITERAL_CSTRING("3glogo.gtimg.com"), // for 3g.163.com
|
||||
NS_LITERAL_CSTRING("info.3g.qq.com"), // for 3g.qq.com
|
||||
NS_LITERAL_CSTRING("3gimg.qq.com"), // for 3g.qq.com
|
||||
NS_LITERAL_CSTRING("img.m.baidu.com"), // for [shucheng|ks].baidu.com
|
||||
NS_LITERAL_CSTRING("m.mogujie.com"),
|
||||
NS_LITERAL_CSTRING("touch.qunar.com"),
|
||||
};
|
||||
static const size_t sNumFullDomainsOnWhitelist =
|
||||
MOZ_ARRAY_LENGTH(sFullDomainsOnWhitelist);
|
||||
|
||||
// Skip 0th (dummy) entry in whitelist, unless a pref is enabled.
|
||||
const size_t firstWhitelistIdx = IsWhitelistingTestDomains() ? 0 : 1;
|
||||
|
||||
for (size_t i = firstWhitelistIdx; i < sNumFullDomainsOnWhitelist; ++i) {
|
||||
if (hostStr == sFullDomainsOnWhitelist[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Checks if the given URI's host is on our "base domain" whitelist
|
||||
// (i.e. if it's a subdomain of some host that we've whitelisted as needing
|
||||
// unprefixing for all its subdomains)
|
||||
static bool
|
||||
IsOnBaseDomainWhitelist(nsIURI* aURI)
|
||||
{
|
||||
static const nsLiteralCString sBaseDomainsOnWhitelist[] = {
|
||||
// 0th entry only active when testing:
|
||||
NS_LITERAL_CSTRING("test2.example.org"),
|
||||
NS_LITERAL_CSTRING("tbcdn.cn"), // for m.taobao.com
|
||||
NS_LITERAL_CSTRING("dpfile.com"), // for m.dianping.com
|
||||
NS_LITERAL_CSTRING("hao123img.com"), // for hao123.com
|
||||
};
|
||||
static const size_t sNumBaseDomainsOnWhitelist =
|
||||
MOZ_ARRAY_LENGTH(sBaseDomainsOnWhitelist);
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
|
||||
if (tldService) {
|
||||
// Skip 0th test-entry in whitelist, unless the testing pref is enabled.
|
||||
const size_t firstWhitelistIdx = IsWhitelistingTestDomains() ? 0 : 1;
|
||||
|
||||
// Right now, the test base-domain "test2.example.org" is the only entry in
|
||||
// its whitelist with a nonzero "depth". So we'll only bother going beyond
|
||||
// 0 depth (to 1) if that entry is enabled. (No point in slowing down the
|
||||
// normal codepath, for the benefit of a disabled test domain.) If we add a
|
||||
// "real" base-domain with a depth of >= 1 to our whitelist, we can get rid
|
||||
// of this conditional & just make this a static variable.
|
||||
const uint32_t maxSubdomainDepth = IsWhitelistingTestDomains() ? 1 : 0;
|
||||
|
||||
for (uint32_t subdomainDepth = 0;
|
||||
subdomainDepth <= maxSubdomainDepth; ++subdomainDepth) {
|
||||
|
||||
// Get the base domain (to depth |subdomainDepth|) from passed-in URI:
|
||||
nsAutoCString baseDomainStr;
|
||||
nsresult rv = tldService->GetBaseDomain(aURI, subdomainDepth,
|
||||
baseDomainStr);
|
||||
if (NS_FAILED(rv)) {
|
||||
// aURI doesn't have |subdomainDepth| levels of subdomains. If we got
|
||||
// here without a match yet, then aURI is not on our whitelist.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare the base domain against each entry in our whitelist:
|
||||
for (size_t i = firstWhitelistIdx; i < sNumBaseDomainsOnWhitelist; ++i) {
|
||||
if (baseDomainStr == sBaseDomainsOnWhitelist[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The actual (non-cached) implementation of IsOnCSSUnprefixingWhitelist():
|
||||
static bool
|
||||
IsOnCSSUnprefixingWhitelistImpl(nsIURI* aURI)
|
||||
{
|
||||
// Check scheme, so we can drop any non-HTTP/HTTPS URIs right away
|
||||
nsAutoCString schemeStr;
|
||||
nsresult rv = aURI->GetScheme(schemeStr);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
// Only proceed if scheme is "http" or "https"
|
||||
if (!(StringBeginsWith(schemeStr, NS_LITERAL_CSTRING("http")) &&
|
||||
(schemeStr.Length() == 4 ||
|
||||
(schemeStr.Length() == 5 && schemeStr[4] == 's')))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (IsOnFullDomainWhitelist(aURI) ||
|
||||
IsOnBaseDomainWhitelist(aURI));
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
nsPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
if (mIsOnCSSUnprefixingWhitelist.isNothing()) {
|
||||
// Value not cached -- perform our lazy whitelist-check.
|
||||
// (NOTE: If our URI is mutable, we just assume it's not on the whitelist,
|
||||
// since our caching strategy won't work. This isn't expected to be common.)
|
||||
mIsOnCSSUnprefixingWhitelist.emplace(
|
||||
mCodebaseImmutable &&
|
||||
IsOnCSSUnprefixingWhitelistImpl(mCodebase));
|
||||
}
|
||||
|
||||
return *mIsOnCSSUnprefixingWhitelist;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************/
|
||||
|
||||
static const char EXPANDED_PRINCIPAL_SPEC[] = "[Expanded Principal]";
|
||||
@@ -823,6 +968,15 @@ nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool
|
||||
nsExpandedPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
// CSS Unprefixing Whitelist is a per-origin thing; doesn't really make sense
|
||||
// for an expanded principal. (And probably shouldn't be needed.)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
|
||||
{
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) override;
|
||||
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
virtual bool IsOnCSSUnprefixingWhitelist() override;
|
||||
#ifdef DEBUG
|
||||
virtual void dumpImpl() override;
|
||||
#endif
|
||||
@@ -102,6 +103,11 @@ public:
|
||||
*/
|
||||
static nsresult GetOriginForURI(nsIURI* aURI, char **aOrigin);
|
||||
|
||||
/**
|
||||
* Called at startup to setup static data, e.g. about:config pref-observers.
|
||||
*/
|
||||
static void InitializeStatics();
|
||||
|
||||
nsCOMPtr<nsIURI> mDomain;
|
||||
nsCOMPtr<nsIURI> mCodebase;
|
||||
uint32_t mAppId;
|
||||
@@ -110,6 +116,7 @@ public:
|
||||
bool mCodebaseImmutable;
|
||||
bool mDomainImmutable;
|
||||
bool mInitialized;
|
||||
mozilla::Maybe<bool> mIsOnCSSUnprefixingWhitelist; // Lazily-computed
|
||||
|
||||
protected:
|
||||
virtual ~nsPrincipal();
|
||||
@@ -149,6 +156,7 @@ public:
|
||||
NS_IMETHOD GetUnknownAppId(bool* aUnknownAppId) override;
|
||||
NS_IMETHOD GetIsNullPrincipal(bool* aIsNullPrincipal) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
virtual bool IsOnCSSUnprefixingWhitelist() override;
|
||||
#ifdef DEBUG
|
||||
virtual void dumpImpl() override;
|
||||
#endif
|
||||
|
||||
@@ -201,6 +201,13 @@ nsSystemPrincipal::GetBaseDomain(nsACString& aBaseDomain)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsSystemPrincipal::IsOnCSSUnprefixingWhitelist()
|
||||
{
|
||||
// chrome stylesheets should not be fed to the CSS Unprefixing Service.
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Methods implementing nsISerializable //
|
||||
//////////////////////////////////////////
|
||||
|
||||
@@ -293,6 +293,8 @@ if test -n "$gonkdir" ; then
|
||||
GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
|
||||
MOZ_AUDIO_OFFLOAD=1
|
||||
MOZ_OMX_DECODER=1
|
||||
MOZ_OMX_ENCODER=1
|
||||
AC_DEFINE(MOZ_OMX_ENCODER)
|
||||
AC_SUBST(MOZ_AUDIO_OFFLOAD)
|
||||
AC_DEFINE(MOZ_AUDIO_OFFLOAD)
|
||||
MOZ_FMP4=
|
||||
@@ -3913,6 +3915,7 @@ MOZ_ANDROID_MLS_STUMBLER=
|
||||
MOZ_ANDROID_SHARE_OVERLAY=
|
||||
ACCESSIBILITY=
|
||||
MOZ_TIME_MANAGER=
|
||||
MOZ_SIMPLEPUSH=
|
||||
MOZ_PAY=
|
||||
MOZ_AUDIO_CHANNEL_MANAGER=
|
||||
NSS_NO_LIBPKIX=
|
||||
@@ -7258,6 +7261,15 @@ if test -n "$MOZ_B2G_CAMERA"; then
|
||||
fi
|
||||
AC_SUBST(MOZ_B2G_CAMERA)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for SimplePush (Gonk usually)
|
||||
dnl This will disable the Push API.
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_SIMPLEPUSH"; then
|
||||
AC_DEFINE(MOZ_SIMPLEPUSH)
|
||||
fi
|
||||
AC_SUBST(MOZ_SIMPLEPUSH)
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Support for Payment API
|
||||
dnl ========================================================
|
||||
|
||||
@@ -99,6 +99,10 @@ static RedirEntry kRedirMap[] = {
|
||||
"webrtc", "chrome://global/content/aboutwebrtc/aboutWebrtc.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT
|
||||
},
|
||||
{
|
||||
"serviceworkers", "chrome://global/content/aboutServiceWorkers.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT
|
||||
},
|
||||
// about:srcdoc is unresolvable by specification. It is included here
|
||||
// because the security manager would disallow srcdoc iframes otherwise.
|
||||
{
|
||||
|
||||
@@ -173,6 +173,7 @@ const mozilla::Module::ContractIDEntry kDocShellContracts[] = {
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "networking", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "webrtc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "srcdoc", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "serviceworkers", &kNS_ABOUT_REDIRECTOR_MODULE_CID },
|
||||
{ NS_URI_LOADER_CONTRACTID, &kNS_URI_LOADER_CID },
|
||||
{ NS_DOCUMENTLOADER_SERVICE_CONTRACTID, &kNS_DOCUMENTLOADER_SERVICE_CID },
|
||||
{ NS_EXTERNALHELPERAPPSERVICE_CONTRACTID, &kNS_EXTERNALHELPERAPPSERVICE_CID },
|
||||
|
||||
@@ -51,6 +51,16 @@ struct AnimationTiming
|
||||
return mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BOTH ||
|
||||
mFillMode == NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS;
|
||||
}
|
||||
bool operator==(const AnimationTiming& aOther) const {
|
||||
return mIterationDuration == aOther.mIterationDuration &&
|
||||
mDelay == aOther.mDelay &&
|
||||
mIterationCount == aOther.mIterationCount &&
|
||||
mDirection == aOther.mDirection &&
|
||||
mFillMode == aOther.mFillMode;
|
||||
}
|
||||
bool operator!=(const AnimationTiming& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -104,6 +114,14 @@ public:
|
||||
}
|
||||
Type GetType() const { return mType; }
|
||||
uint32_t GetSteps() const { return mSteps; }
|
||||
bool operator==(const ComputedTimingFunction& aOther) const {
|
||||
return mType == aOther.mType &&
|
||||
mTimingFunction == aOther.mTimingFunction &&
|
||||
mSteps == aOther.mSteps;
|
||||
}
|
||||
bool operator!=(const ComputedTimingFunction& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
private:
|
||||
Type mType;
|
||||
@@ -116,12 +134,31 @@ struct AnimationPropertySegment
|
||||
float mFromKey, mToKey;
|
||||
StyleAnimationValue mFromValue, mToValue;
|
||||
ComputedTimingFunction mTimingFunction;
|
||||
|
||||
bool operator==(const AnimationPropertySegment& aOther) const {
|
||||
return mFromKey == aOther.mFromKey &&
|
||||
mToKey == aOther.mToKey &&
|
||||
mFromValue == aOther.mFromValue &&
|
||||
mToValue == aOther.mToValue &&
|
||||
mTimingFunction == aOther.mTimingFunction;
|
||||
}
|
||||
bool operator!=(const AnimationPropertySegment& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
struct AnimationProperty
|
||||
{
|
||||
nsCSSProperty mProperty;
|
||||
InfallibleTArray<AnimationPropertySegment> mSegments;
|
||||
|
||||
bool operator==(const AnimationProperty& aOther) const {
|
||||
return mProperty == aOther.mProperty &&
|
||||
mSegments == aOther.mSegments;
|
||||
}
|
||||
bool operator!=(const AnimationProperty& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
struct ElementPropertyTransition;
|
||||
|
||||
@@ -128,6 +128,7 @@ AnimationPlayer::SetSource(Animation* aSource)
|
||||
if (mSource) {
|
||||
mSource->SetParentTime(GetCurrentTime());
|
||||
}
|
||||
UpdateRelevance();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -213,6 +214,8 @@ AnimationPlayer::Cancel()
|
||||
|
||||
mHoldTime.SetNull();
|
||||
mStartTime.SetNull();
|
||||
|
||||
UpdateSourceContent();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -226,6 +229,20 @@ AnimationPlayer::IsRunning() const
|
||||
return computedTiming.mPhase == ComputedTiming::AnimationPhase_Active;
|
||||
}
|
||||
|
||||
void
|
||||
AnimationPlayer::UpdateRelevance()
|
||||
{
|
||||
bool wasRelevant = mIsRelevant;
|
||||
mIsRelevant = HasCurrentSource() || HasInEffectSource();
|
||||
|
||||
// Notify animation observers.
|
||||
if (wasRelevant && !mIsRelevant) {
|
||||
nsNodeUtils::AnimationRemoved(this);
|
||||
} else if (!wasRelevant && mIsRelevant) {
|
||||
nsNodeUtils::AnimationAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AnimationPlayer::CanThrottle() const
|
||||
{
|
||||
@@ -356,6 +373,7 @@ AnimationPlayer::UpdateSourceContent()
|
||||
{
|
||||
if (mSource) {
|
||||
mSource->SetParentTime(GetCurrentTime());
|
||||
UpdateRelevance();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class AnimationPlayer : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
protected:
|
||||
virtual ~AnimationPlayer() { }
|
||||
virtual ~AnimationPlayer() {}
|
||||
|
||||
public:
|
||||
explicit AnimationPlayer(AnimationTimeline* aTimeline)
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
, mIsPending(false)
|
||||
, mIsRunningOnCompositor(false)
|
||||
, mIsPreviousStateFinished(false)
|
||||
, mIsRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -185,6 +186,9 @@ public:
|
||||
return GetSource() && GetSource()->IsInEffect();
|
||||
}
|
||||
|
||||
bool IsRelevant() const { return mIsRelevant; }
|
||||
void UpdateRelevance();
|
||||
|
||||
void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; }
|
||||
void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; }
|
||||
|
||||
@@ -250,6 +254,9 @@ protected:
|
||||
// probably remove this and check if the promise has been settled yet
|
||||
// or not instead.
|
||||
bool mIsPreviousStateFinished; // Spec calls this "previous finished state"
|
||||
// Indicates that the player should be exposed in an element's
|
||||
// getAnimationPlayers() list.
|
||||
bool mIsRelevant;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
[chrome/test_animation_observers.html]
|
||||
[chrome/test_running_on_compositor.html]
|
||||
|
||||
@@ -0,0 +1,698 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test chrome-only MutationObserver animation notifications</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<style>
|
||||
@keyframes anim {
|
||||
to { transform: translate(100px); }
|
||||
}
|
||||
#target {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: yellow;
|
||||
line-height: 16px;
|
||||
}
|
||||
</style>
|
||||
<div id=container><div id=target></div></div>
|
||||
<script>
|
||||
var div = document.getElementById("target");
|
||||
var gRecords = [];
|
||||
var gRecordPromiseResolvers = [];
|
||||
var gObserver = new MutationObserver(function(newRecords) {
|
||||
dump(`got a record ${newRecords[0].addedAnimations.length}/${newRecords[0].changedAnimations.length}/${newRecords[0].removedAnimations.length}\n`);
|
||||
gRecords.push(...newRecords);
|
||||
|
||||
var resolvers = gRecordPromiseResolvers;
|
||||
gRecordPromiseResolvers = [];
|
||||
resolvers.forEach(fn => fn());
|
||||
});
|
||||
|
||||
// Asynchronous testing framework based on layout/style/test/animation_utils.js.
|
||||
|
||||
var gTests = [];
|
||||
var gCurrentTestName;
|
||||
|
||||
function addAsyncAnimTest(aName, aOptions, aTestGenerator) {
|
||||
aTestGenerator.testName = aName;
|
||||
aTestGenerator.options = aOptions || {};
|
||||
gTests.push(aTestGenerator);
|
||||
}
|
||||
|
||||
function runAsyncTest(aTestGenerator) {
|
||||
return await_frame().then(function() {
|
||||
var generator;
|
||||
|
||||
function step(arg) {
|
||||
var next;
|
||||
try {
|
||||
next = generator.next(arg);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
if (next.done) {
|
||||
return Promise.resolve(next.value);
|
||||
} else {
|
||||
return Promise.resolve(next.value).then(step);
|
||||
}
|
||||
}
|
||||
|
||||
var subtree = aTestGenerator.options.subtree;
|
||||
|
||||
gCurrentTestName = aTestGenerator.testName;
|
||||
if (subtree) {
|
||||
gCurrentTestName += ":subtree";
|
||||
}
|
||||
|
||||
gRecords = [];
|
||||
gObserver.disconnect();
|
||||
gObserver.observe(aTestGenerator.options.observe,
|
||||
{ animations: true, subtree: subtree});
|
||||
|
||||
generator = aTestGenerator();
|
||||
return step();
|
||||
});
|
||||
};
|
||||
|
||||
function runAllAsyncTests() {
|
||||
return gTests.reduce(function(sequence, test) {
|
||||
return sequence.then(() => runAsyncTest(test));
|
||||
}, Promise.resolve());
|
||||
}
|
||||
|
||||
// Wrap is and ok with versions that prepend the current sub-test name
|
||||
// to the assertion description.
|
||||
var old_is = is, old_ok = ok;
|
||||
is = function(a, b, message) {
|
||||
if (gCurrentTestName && message) {
|
||||
message = `[${gCurrentTestName}] ${message}`;
|
||||
}
|
||||
old_is(a, b, message);
|
||||
}
|
||||
ok = function(a, message) {
|
||||
if (gCurrentTestName && message) {
|
||||
message = `[${gCurrentTestName}] ${message}`;
|
||||
}
|
||||
old_ok(a, message);
|
||||
}
|
||||
|
||||
// Returns a Promise that is resolved by a requestAnimationFrame callback.
|
||||
function await_frame() {
|
||||
return new Promise(function(aResolve) {
|
||||
requestAnimationFrame(function() {
|
||||
aResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Adds an event listener and returns a Promise that is resolved when the
|
||||
// event listener is called.
|
||||
function await_event(aElement, aEventName) {
|
||||
return new Promise(function(aResolve) {
|
||||
function listener(aEvent) {
|
||||
aElement.removeEventListener(aEventName, listener);
|
||||
aResolve();
|
||||
}
|
||||
aElement.addEventListener(aEventName, listener, false);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a Promise that is resolved after a given timeout duration.
|
||||
function await_timeout(aTimeout) {
|
||||
return new Promise(function(aResolve) {
|
||||
setTimeout(function() {
|
||||
aResolve();
|
||||
}, aTimeout);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a Promise that is resolved when the MutationObserver is next
|
||||
// invoked.
|
||||
function await_records() {
|
||||
return new Promise(function(aResolve) {
|
||||
gRecordPromiseResolvers.push(aResolve);
|
||||
});
|
||||
}
|
||||
|
||||
function assert_record_list(actual, expected, desc, index, listName) {
|
||||
is(actual.length, expected.length, `${desc} - record[${index}].${listName} length`);
|
||||
if (actual.length != expected.length) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
ok(actual.indexOf(expected[i]) != -1,
|
||||
`${desc} - record[${index}].${listName} contains expected AnimationPlayer`);
|
||||
}
|
||||
}
|
||||
|
||||
function assert_records(expected, desc) {
|
||||
var records = gRecords;
|
||||
gRecords = [];
|
||||
is(records.length, expected.length, `${desc} - number of records`);
|
||||
if (records.length != expected.length) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < records.length; i++) {
|
||||
assert_record_list(records[i].addedAnimations, expected[i].added, desc, i, "addedAnimations");
|
||||
assert_record_list(records[i].changedAnimations, expected[i].changed, desc, i, "changedAnimations");
|
||||
assert_record_list(records[i].removedAnimations, expected[i].removed, desc, i, "removedAnimations");
|
||||
}
|
||||
}
|
||||
|
||||
// -- Tests ------------------------------------------------------------------
|
||||
|
||||
// We run all tests first targetting the div and observing the div, then again
|
||||
// targetting the div and observing its parent while using the subtree:true
|
||||
// MutationObserver option.
|
||||
|
||||
[
|
||||
{ observe: div, target: div, subtree: false },
|
||||
{ observe: div.parentNode, target: div, subtree: true },
|
||||
].forEach(function(aOptions) {
|
||||
|
||||
var e = aOptions.target;
|
||||
|
||||
// Test that starting a single transition that completes normally
|
||||
// dispatches an added notification and then a removed notification.
|
||||
addAsyncAnimTest("single_transition", aOptions, function*() {
|
||||
// Start a transition.
|
||||
e.style = "transition: background-color 0.001s; background-color: lime;";
|
||||
|
||||
// Register for the end of the transition.
|
||||
var transitionEnd = await_event(e, "transitionend");
|
||||
|
||||
// The transition should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
yield transitionEnd;
|
||||
|
||||
// After the transition has finished, the AnimationPlayer should disappear.
|
||||
is(e.getAnimationPlayers().length, 0, "getAnimationPlayers().length after transition end");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after transition end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single transition that is cancelled by resetting
|
||||
// the transition-property property dispatches an added notification and
|
||||
// then a removed notification.
|
||||
addAsyncAnimTest("single_transition_cancelled_property", aOptions, function*() {
|
||||
// Start a long transition.
|
||||
e.style = "transition: background-color 100s; background-color: lime;";
|
||||
|
||||
// The transition should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
// Cancel the transition by setting transition-property.
|
||||
e.style.transitionProperty = "none";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after transition end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single transition that is cancelled by setting
|
||||
// style to the currently animated value dispatches an added
|
||||
// notification and then a removed notification.
|
||||
addAsyncAnimTest("single_transition_cancelled_value", aOptions, function*() {
|
||||
// Start a long transition with a predictable value.
|
||||
e.style = "transition: background-color 100s steps(2, end) -51s; background-color: lime;";
|
||||
|
||||
// The transition should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
// Cancel the transition by setting the current animation value.
|
||||
var value = "rgb(128, 255, 0)";
|
||||
is(getComputedStyle(e).backgroundColor, value, "half-way transition value");
|
||||
e.style.backgroundColor = value;
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after transition end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single transition that is cancelled by setting
|
||||
// style to a non-interpolable value dispatches an added notification
|
||||
// and then a removed notification.
|
||||
addAsyncAnimTest("single_transition_cancelled_noninterpolable", aOptions, function*() {
|
||||
// Start a long transition.
|
||||
e.style = "transition: line-height 100s; line-height: 100px;";
|
||||
|
||||
// The transition should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
// Cancel the transition by setting line-height to a non-interpolable value.
|
||||
e.style.lineHeight = "normal";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after transition end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single transition and then reversing it
|
||||
// dispatches an added notification, then a simultaneous removed and
|
||||
// added notification, then a removed notification once finished.
|
||||
addAsyncAnimTest("single_transition_reversed", aOptions, function*() {
|
||||
// Start a long transition.
|
||||
e.style = "transition: background-color 100s step-start; background-color: lime;";
|
||||
|
||||
// The transition should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition start");
|
||||
|
||||
var firstPlayer = players[0];
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [firstPlayer], changed: [], removed: [] }],
|
||||
"records after transition start");
|
||||
|
||||
// Wait a bit longer for the transition to take effect.
|
||||
yield await_frame();
|
||||
|
||||
// Reverse the transition by setting the background-color back to its
|
||||
// original value.
|
||||
e.style.backgroundColor = "yellow";
|
||||
|
||||
// The reversal should cause the creation of a new AnimationPlayer.
|
||||
players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after transition reversal");
|
||||
|
||||
var secondPlayer = players[0];
|
||||
|
||||
// Wait for the single MutationRecord for the removal of the original
|
||||
// AnimationPlayer and the addition of the new AnimationPlayer to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [secondPlayer], changed: [], removed: [firstPlayer] }],
|
||||
"records after transition reversal");
|
||||
|
||||
// Cancel the transition.
|
||||
e.style.transitionProperty = "none";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: [secondPlayer] }],
|
||||
"records after transition end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that multiple transitions starting and ending on an element
|
||||
// at the same time get batched up into a single MutationRecord.
|
||||
addAsyncAnimTest("multiple_transitions", aOptions, function*() {
|
||||
// Start three long transitions.
|
||||
e.style = "transition-duration: 100s; " +
|
||||
"transition-property: color, background-color, line-height; " +
|
||||
"color: blue; background-color: lime; line-height: 24px;";
|
||||
|
||||
// The transitions should cause the creation of three AnimationPlayers.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 3, "getAnimationPlayers().length after transition starts");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer additions to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after transition starts");
|
||||
|
||||
// Wait for the AnimationPlayers to get going.
|
||||
yield await_frame();
|
||||
|
||||
is(players.filter(p => p.playState == "running").length, 3, "number of running AnimationPlayers");
|
||||
|
||||
// Cancel one of the transitions by setting transition-property.
|
||||
e.style.transitionProperty = "background-color, line-height";
|
||||
|
||||
var colorPlayer = players.filter(p => p.playState != "running");
|
||||
var otherPlayers = players.filter(p => p.playState == "running");
|
||||
|
||||
is(colorPlayer.length, 1, "number of non-running AnimationPlayers after cancelling one");
|
||||
is(otherPlayers.length, 2, "number of running AnimationPlayers after cancelling one");
|
||||
|
||||
// Wait for a MutationRecord for one of the AnimationPlayer
|
||||
// removals to be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: colorPlayer }],
|
||||
"records after color transition end");
|
||||
|
||||
// Cancel the remaining transitions.
|
||||
e.style.transitionProperty = "none";
|
||||
|
||||
// Wait for the MutationRecord for the other two AnimationPlayer
|
||||
// removals to be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: otherPlayers }],
|
||||
"records after other transition ends");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that completes normally
|
||||
// dispatches an added notification and then a removed notification.
|
||||
addAsyncAnimTest("single_animation", aOptions, function*() {
|
||||
// Start an animation.
|
||||
e.style = "animation: anim 0.001s;";
|
||||
|
||||
// Register for the end of the animation.
|
||||
var animationEnd = await_event(e, "animationend");
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
yield animationEnd;
|
||||
|
||||
// After the animation has finished, the AnimationPlayer should disappear.
|
||||
is(e.getAnimationPlayers().length, 0, "getAnimationPlayers().length after animation end");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that is cancelled by resetting
|
||||
// the animation-name property dispatches an added notification and
|
||||
// then a removed notification.
|
||||
addAsyncAnimTest("single_animation_cancelled_name", aOptions, function*() {
|
||||
// Start a long animation.
|
||||
e.style = "animation: anim 100s;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Cancel the animation by setting animation-name.
|
||||
e.style.animationName = "none";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that is cancelled by updating
|
||||
// the animation-duration property dispatches an added notification and
|
||||
// then a removed notification.
|
||||
addAsyncAnimTest("single_animation_cancelled_duration", aOptions, function*() {
|
||||
// Start a long animation.
|
||||
e.style = "animation: anim 100s;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Advance the animation by a second.
|
||||
players[0].currentTime += 1000;
|
||||
|
||||
// Cancel the animation by setting animation-duration to a value less
|
||||
// than a second.
|
||||
e.style.animationDuration = "0.1s";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that is cancelled by updating
|
||||
// the animation-delay property dispatches an added notification and
|
||||
// then a removed notification.
|
||||
addAsyncAnimTest("single_animation_cancelled_delay", aOptions, function*() {
|
||||
// Start a long animation.
|
||||
e.style = "animation: anim 100s;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Cancel the animation by setting animation-delay.
|
||||
e.style.animationDelay = "-200s";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that is cancelled by updating
|
||||
// the animation-fill-mode property dispatches an added notification and
|
||||
// then a removed notification.
|
||||
addAsyncAnimTest("single_animation_cancelled_fill", aOptions, function*() {
|
||||
// Start a short, filled animation.
|
||||
e.style = "animation: anim 0.001s forwards;";
|
||||
|
||||
// Register for the end of the animation.
|
||||
var animationEnd = await_event(e, "animationend");
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Wait until we are definitely filling.
|
||||
yield animationEnd;
|
||||
|
||||
// No changes to the list of animations at this point.
|
||||
assert_records([], "records after animation starts filling");
|
||||
|
||||
// Cancel the animation by setting animation-fill-mode.
|
||||
e.style.animationFillMode = "none";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that starting a single animation that is cancelled by updating
|
||||
// the animation-iteration-count property dispatches an added notification
|
||||
// and then a removed notification.
|
||||
addAsyncAnimTest("single_animation_cancelled_fill", aOptions, function*() {
|
||||
// Start a short, repeated animation.
|
||||
e.style = "animation: anim 0.5s infinite;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Advance the animation until we are past the first iteration.
|
||||
players[0].currentTime += 1000;
|
||||
|
||||
// No changes to the list of animations at this point.
|
||||
assert_records([], "records after animation starts repeating");
|
||||
|
||||
// Cancel the animation by setting animation-iteration-count.
|
||||
e.style.animationIterationCount = "1";
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer removal to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that updating an animation property dispatches a changed notification.
|
||||
[
|
||||
{ name: "duration", prop: "animationDuration", val: "200s" },
|
||||
{ name: "timing", prop: "animationTimingFunction", val: "linear" },
|
||||
{ name: "iteration", prop: "animationIterationCount", val: "2" },
|
||||
{ name: "direction", prop: "animationDirection", val: "reverse" },
|
||||
{ name: "state", prop: "animationPlayState", val: "paused" },
|
||||
{ name: "delay", prop: "animationDelay", val: "-1s" },
|
||||
{ name: "fill", prop: "animationFillMode", val: "both" },
|
||||
].forEach(function(aChangeTest) {
|
||||
addAsyncAnimTest(`single_animation_change_${aChangeTest.name}`, aOptions, function*() {
|
||||
// Start a long animation.
|
||||
e.style = "animation: anim 100s;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Change a property of the animation such that it keeps running.
|
||||
e.style[aChangeTest.prop] = aChangeTest.val;
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer change to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: players, removed: [] }],
|
||||
"records after animation change");
|
||||
|
||||
// Cancel the animation.
|
||||
e.style.animationName = "none";
|
||||
|
||||
// Wait for the addition, change and removal MutationRecords to be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
});
|
||||
|
||||
// Test that a non-cancelling change to an animation followed immediately by a
|
||||
// cancelling change will only send an animation removal notification.
|
||||
addAsyncAnimTest("coalesce_change_cancel", aOptions, function*() {
|
||||
// Start a long animation.
|
||||
e.style = "animation: anim 100s;";
|
||||
|
||||
// The animation should cause the creation of a single AnimationPlayer.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 1, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// Wait for the single MutationRecord for the AnimationPlayer addition to
|
||||
// be delivered.
|
||||
yield await_frame();
|
||||
assert_records([{ added: players, changed: [], removed: [] }],
|
||||
"records after animation start");
|
||||
|
||||
// Update the animation's delay such that it is still running.
|
||||
e.style.animationDelay = "-1s";
|
||||
|
||||
// Then cancel the animation by updating its duration.
|
||||
e.style.animationDuration = "0.5s";
|
||||
|
||||
// We should get a single removal notification.
|
||||
yield await_frame();
|
||||
assert_records([{ added: [], changed: [], removed: players }],
|
||||
"records after animation end");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
|
||||
// Test that attempting to start an animation that should already be finished
|
||||
// does not send any notifications.
|
||||
addAsyncAnimTest("already_finished", aOptions, function*() {
|
||||
// Start an animation that should already be finished.
|
||||
e.style = "animation: anim 1s -2s;";
|
||||
|
||||
// The animation should cause no AnimationPlayers to be created.
|
||||
var players = e.getAnimationPlayers();
|
||||
is(players.length, 0, "getAnimationPlayers().length after animation start");
|
||||
|
||||
// And we should get no notifications.
|
||||
yield await_frame();
|
||||
assert_records([], "records after attempted animation start");
|
||||
|
||||
e.style = "";
|
||||
});
|
||||
});
|
||||
|
||||
// Run the tests.
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
runAllAsyncTests().then(function() {
|
||||
SimpleTest.finish();
|
||||
}, function(aError) {
|
||||
ok(false, "Something failed: " + aError);
|
||||
});
|
||||
</script>
|
||||
@@ -507,15 +507,15 @@ AudioChannelService::ProcessContentOrNormalChannelIsActive(uint64_t aChildID)
|
||||
|
||||
void
|
||||
AudioChannelService::SetDefaultVolumeControlChannel(int32_t aChannel,
|
||||
bool aHidden)
|
||||
bool aVisible)
|
||||
{
|
||||
SetDefaultVolumeControlChannelInternal(aChannel, aHidden,
|
||||
SetDefaultVolumeControlChannelInternal(aChannel, aVisible,
|
||||
CONTENT_PROCESS_ID_MAIN);
|
||||
}
|
||||
|
||||
void
|
||||
AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel,
|
||||
bool aHidden,
|
||||
bool aVisible,
|
||||
uint64_t aChildID)
|
||||
{
|
||||
if (XRE_GetProcessType() != GoannaProcessType_Default) {
|
||||
@@ -525,15 +525,26 @@ AudioChannelService::SetDefaultVolumeControlChannelInternal(int32_t aChannel,
|
||||
// If this child is in the background and mDefChannelChildID is set to
|
||||
// others then it means other child in the foreground already set it's
|
||||
// own default channel already.
|
||||
if ((!aHidden && mDefChannelChildID != aChildID) ||
|
||||
(mDefChannelChildID != aChildID &&
|
||||
mDefChannelChildID != CONTENT_PROCESS_ID_UNKNOWN)) {
|
||||
if (!aVisible && mDefChannelChildID != aChildID) {
|
||||
return;
|
||||
}
|
||||
// Workaround for the call screen app. The call screen app is running on the
|
||||
// main process, that will results in wrong visible state. Because we use the
|
||||
// docshell's active state as visible state, the main process is always
|
||||
// active. Therefore, we will see the strange situation that the visible
|
||||
// state of the call screen is always true. If the mDefChannelChildID is set
|
||||
// to others then it means other child in the foreground already set it's
|
||||
// own default channel already.
|
||||
// Summary :
|
||||
// Child process : foreground app always can set type.
|
||||
// Parent process : check the mDefChannelChildID.
|
||||
else if (aChildID == CONTENT_PROCESS_ID_MAIN &&
|
||||
mDefChannelChildID != CONTENT_PROCESS_ID_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDefChannelChildID = aChildID;
|
||||
nsString channelName;
|
||||
|
||||
mDefChannelChildID = aVisible ? aChildID : CONTENT_PROCESS_ID_UNKNOWN;
|
||||
nsAutoString channelName;
|
||||
if (aChannel == -1) {
|
||||
channelName.AssignASCII("unknown");
|
||||
} else {
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
* AudioChannel enum.
|
||||
*/
|
||||
virtual void SetDefaultVolumeControlChannel(int32_t aChannel,
|
||||
bool aHidden);
|
||||
bool aVisible);
|
||||
|
||||
bool AnyAudioChannelIsActive();
|
||||
|
||||
@@ -153,7 +153,7 @@ protected:
|
||||
|
||||
/* Send the default-volume-channel-changed notification */
|
||||
void SetDefaultVolumeControlChannelInternal(int32_t aChannel,
|
||||
bool aHidden, uint64_t aChildID);
|
||||
bool aVisible, uint64_t aChildID);
|
||||
|
||||
AudioChannelState CheckTelephonyPolicy(AudioChannel aChannel,
|
||||
uint64_t aChildID);
|
||||
|
||||
@@ -3255,7 +3255,7 @@ Element::GetAnimationPlayers(nsTArray<nsRefPtr<AnimationPlayer> >& aPlayers)
|
||||
playerIdx < collection->mPlayers.Length();
|
||||
playerIdx++) {
|
||||
AnimationPlayer* player = collection->mPlayers[playerIdx];
|
||||
if (player->HasCurrentSource() || player->HasInEffectSource()) {
|
||||
if (player->IsRelevant()) {
|
||||
aPlayers.AppendElement(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ EXPORTS += [
|
||||
'nsGkAtoms.h',
|
||||
'nsHostObjectProtocolHandler.h',
|
||||
'nsHostObjectURI.h',
|
||||
'nsIAnimationObserver.h',
|
||||
'nsIAttribute.h',
|
||||
'nsIContent.h',
|
||||
'nsIContentInlines.h',
|
||||
@@ -117,6 +118,7 @@ EXPORTS += [
|
||||
'nsSandboxFlags.h',
|
||||
'nsScriptLoader.h',
|
||||
'nsStructuredCloneContainer.h',
|
||||
'nsStubAnimationObserver.h',
|
||||
'nsStubDocumentObserver.h',
|
||||
'nsStubMutationObserver.h',
|
||||
'nsStyledElement.h',
|
||||
@@ -300,6 +302,7 @@ UNIFIED_SOURCES += [
|
||||
'nsScriptLoader.cpp',
|
||||
'nsScriptNameSpaceManager.cpp',
|
||||
'nsStructuredCloneContainer.cpp',
|
||||
'nsStubAnimationObserver.cpp',
|
||||
'nsStubDocumentObserver.cpp',
|
||||
'nsStubMutationObserver.cpp',
|
||||
'nsStyledElement.cpp',
|
||||
|
||||
@@ -6839,7 +6839,7 @@ nsContentUtils::GetSelectionInTextControl(Selection* aSelection,
|
||||
{
|
||||
MOZ_ASSERT(aSelection && aRoot);
|
||||
|
||||
if (!aSelection->GetRangeCount()) {
|
||||
if (!aSelection->RangeCount()) {
|
||||
// Nothing selected
|
||||
aOutStartOffset = aOutEndOffset = 0;
|
||||
return;
|
||||
@@ -6900,7 +6900,7 @@ nsContentUtils::GetSelectionBoundingRect(Selection* aSel)
|
||||
res = nsLayoutUtils::TransformFrameRectToAncestor(frame, res, relativeTo);
|
||||
}
|
||||
} else {
|
||||
int32_t rangeCount = aSel->GetRangeCount();
|
||||
int32_t rangeCount = aSel->RangeCount();
|
||||
nsLayoutUtils::RectAccumulator accumulator;
|
||||
for (int32_t idx = 0; idx < rangeCount; ++idx) {
|
||||
nsRange* range = aSel->GetRangeAt(idx);
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
0x45f27d10, 0x987b, 0x11d2, \
|
||||
{0xbd, 0x40, 0x00, 0x10, 0x5a, 0xa4, 0x5e, 0x89} }
|
||||
|
||||
#define SERVICEWORKERPERIODICUPDATER_CONTRACTID \
|
||||
"@mozilla.org/service-worker-periodic-updater;1"
|
||||
|
||||
//The dom cannot provide the crypto or pkcs11 classes that
|
||||
//were used in older days, so if someone wants to provide
|
||||
//the service they must implement an object and give it
|
||||
|
||||
@@ -56,6 +56,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord,
|
||||
mTarget,
|
||||
mPreviousSibling, mNextSibling,
|
||||
mAddedNodes, mRemovedNodes,
|
||||
mAddedAnimations, mRemovedAnimations,
|
||||
mChangedAnimations,
|
||||
mNext, mOwner)
|
||||
|
||||
// Observer
|
||||
@@ -267,7 +269,7 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
|
||||
// Try to avoid creating transient observer if the node
|
||||
// already has an observer observing the same set of nodes.
|
||||
nsMutationReceiver* orig = GetParent() ? GetParent() : this;
|
||||
if (Observer()->GetReceiverFor(aChild, false) != orig) {
|
||||
if (Observer()->GetReceiverFor(aChild, false, false) != orig) {
|
||||
bool transientExists = false;
|
||||
nsCOMArray<nsMutationReceiver>* transientReceivers = nullptr;
|
||||
Observer()->mTransientReceivers.Get(aChild, &transientReceivers);
|
||||
@@ -285,7 +287,13 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
|
||||
if (!transientExists) {
|
||||
// Make sure the elements which are removed from the
|
||||
// subtree are kept in the same observation set.
|
||||
transientReceivers->AppendObject(new nsMutationReceiver(aChild, orig));
|
||||
nsMutationReceiver* tr;
|
||||
if (orig->Animations()) {
|
||||
tr = nsAnimationReceiver::Create(aChild, orig);
|
||||
} else {
|
||||
tr = nsMutationReceiver::Create(aChild, orig);
|
||||
}
|
||||
transientReceivers->AppendObject(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,6 +322,87 @@ void nsMutationReceiver::NodeWillBeDestroyed(const nsINode *aNode)
|
||||
Disconnect(true);
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer,
|
||||
AnimationMutation aMutationType)
|
||||
{
|
||||
Animation* source = aPlayer->GetSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element* animationTarget = source->GetTarget();
|
||||
if (!animationTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Animations() || !(Subtree() || animationTarget == Target()) ||
|
||||
animationTarget->ChromeOnlyAccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsAutoAnimationMutationBatch::IsBatching()) {
|
||||
if (nsAutoAnimationMutationBatch::GetBatchTarget() != animationTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMutationType) {
|
||||
case eAnimationMutation_Added:
|
||||
nsAutoAnimationMutationBatch::AnimationAdded(aPlayer);
|
||||
break;
|
||||
case eAnimationMutation_Changed:
|
||||
nsAutoAnimationMutationBatch::AnimationChanged(aPlayer);
|
||||
break;
|
||||
case eAnimationMutation_Removed:
|
||||
nsAutoAnimationMutationBatch::AnimationRemoved(aPlayer);
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoAnimationMutationBatch::AddObserver(Observer());
|
||||
return;
|
||||
}
|
||||
|
||||
nsDOMMutationRecord* m =
|
||||
Observer()->CurrentRecord(nsGkAtoms::animations);
|
||||
|
||||
NS_ASSERTION(!m->mTarget, "Wrong target!");
|
||||
|
||||
m->mTarget = animationTarget;
|
||||
|
||||
switch (aMutationType) {
|
||||
case eAnimationMutation_Added:
|
||||
m->mAddedAnimations.AppendElement(aPlayer);
|
||||
break;
|
||||
case eAnimationMutation_Changed:
|
||||
m->mChangedAnimations.AppendElement(aPlayer);
|
||||
break;
|
||||
case eAnimationMutation_Removed:
|
||||
m->mRemovedAnimations.AppendElement(aPlayer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationReceiver::AnimationAdded(AnimationPlayer* aPlayer)
|
||||
{
|
||||
RecordAnimationMutation(aPlayer, eAnimationMutation_Added);
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationReceiver::AnimationChanged(AnimationPlayer* aPlayer)
|
||||
{
|
||||
RecordAnimationMutation(aPlayer, eAnimationMutation_Changed);
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationReceiver::AnimationRemoved(AnimationPlayer* aPlayer)
|
||||
{
|
||||
RecordAnimationMutation(aPlayer, eAnimationMutation_Removed);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsAnimationReceiver, nsMutationReceiver,
|
||||
nsIAnimationObserver)
|
||||
|
||||
// Observer
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver)
|
||||
@@ -353,8 +442,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMutationObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
nsMutationReceiver*
|
||||
nsDOMMutationObserver::GetReceiverFor(nsINode* aNode, bool aMayCreate)
|
||||
nsDOMMutationObserver::GetReceiverFor(nsINode* aNode, bool aMayCreate,
|
||||
bool aWantsAnimations)
|
||||
{
|
||||
MOZ_ASSERT(aMayCreate || !aWantsAnimations,
|
||||
"the value of aWantsAnimations doesn't matter when aMayCreate is "
|
||||
"false, so just pass in false for it");
|
||||
|
||||
if (!aMayCreate && !aNode->MayHaveDOMMutationObserver()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -368,7 +462,12 @@ nsDOMMutationObserver::GetReceiverFor(nsINode* aNode, bool aMayCreate)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsMutationReceiver* r = new nsMutationReceiver(aNode, this);
|
||||
nsMutationReceiver* r;
|
||||
if (aWantsAnimations) {
|
||||
r = nsAnimationReceiver::Create(aNode, this);
|
||||
} else {
|
||||
r = nsMutationReceiver::Create(aNode, this);
|
||||
}
|
||||
mReceivers.AppendObject(r);
|
||||
return r;
|
||||
}
|
||||
@@ -387,7 +486,7 @@ nsDOMMutationObserver::GetAllSubtreeObserversFor(nsINode* aNode,
|
||||
nsINode* n = aNode;
|
||||
while (n) {
|
||||
if (n->MayHaveDOMMutationObserver()) {
|
||||
nsMutationReceiver* r = GetReceiverFor(n, false);
|
||||
nsMutationReceiver* r = GetReceiverFor(n, false, false);
|
||||
if (r && r->Subtree() && !aReceivers.Contains(r)) {
|
||||
aReceivers.AppendElement(r);
|
||||
// If we've found all the receivers the observer has,
|
||||
@@ -467,6 +566,10 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
bool characterDataOldValue =
|
||||
aOptions.mCharacterDataOldValue.WasPassed() &&
|
||||
aOptions.mCharacterDataOldValue.Value();
|
||||
bool animations =
|
||||
aOptions.mAnimations.WasPassed() &&
|
||||
aOptions.mAnimations.Value() &&
|
||||
nsContentUtils::ThreadsafeIsCallerChrome();
|
||||
|
||||
if (!aOptions.mAttributes.WasPassed() &&
|
||||
(aOptions.mAttributeOldValue.WasPassed() ||
|
||||
@@ -479,7 +582,7 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
characterData = true;
|
||||
}
|
||||
|
||||
if (!(childList || attributes || characterData)) {
|
||||
if (!(childList || attributes || characterData || animations)) {
|
||||
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
|
||||
return;
|
||||
}
|
||||
@@ -522,7 +625,7 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
}
|
||||
}
|
||||
|
||||
nsMutationReceiver* r = GetReceiverFor(&aTarget, true);
|
||||
nsMutationReceiver* r = GetReceiverFor(&aTarget, true, animations);
|
||||
r->SetChildList(childList);
|
||||
r->SetAttributes(attributes);
|
||||
r->SetCharacterData(characterData);
|
||||
@@ -531,6 +634,7 @@ nsDOMMutationObserver::Observe(nsINode& aTarget,
|
||||
r->SetCharacterDataOldValue(characterDataOldValue);
|
||||
r->SetAttributeFilter(filters);
|
||||
r->SetAllAttributes(allAttrs);
|
||||
r->SetAnimations(animations);
|
||||
r->RemoveClones();
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -582,6 +686,7 @@ nsDOMMutationObserver::GetObservingInfo(nsTArray<Nullable<MutationObservingInfo>
|
||||
info.mSubtree = mr->Subtree();
|
||||
info.mAttributeOldValue.Construct(mr->AttributeOldValue());
|
||||
info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue());
|
||||
info.mAnimations.Construct(mr->Animations());
|
||||
nsCOMArray<nsIAtom>& filters = mr->AttributeFilter();
|
||||
if (filters.Count()) {
|
||||
info.mAttributeFilter.Construct();
|
||||
@@ -852,10 +957,16 @@ nsAutoMutationBatch::Done()
|
||||
for (uint32_t k = 0; k < allObservers.Length(); ++k) {
|
||||
nsMutationReceiver* r = allObservers[k];
|
||||
nsMutationReceiver* orig = r->GetParent() ? r->GetParent() : r;
|
||||
if (ob->GetReceiverFor(removed, false) != orig) {
|
||||
if (ob->GetReceiverFor(removed, false, false) != orig) {
|
||||
// Make sure the elements which are removed from the
|
||||
// subtree are kept in the same observation set.
|
||||
transientReceivers->AppendObject(new nsMutationReceiver(removed, orig));
|
||||
nsMutationReceiver* tr;
|
||||
if (orig->Animations()) {
|
||||
tr = nsAnimationReceiver::Create(removed, orig);
|
||||
} else {
|
||||
tr = nsMutationReceiver::Create(removed, orig);
|
||||
}
|
||||
transientReceivers->AppendObject(tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -882,3 +993,45 @@ nsAutoMutationBatch::Done()
|
||||
}
|
||||
nsDOMMutationObserver::LeaveMutationHandling();
|
||||
}
|
||||
|
||||
nsAutoAnimationMutationBatch*
|
||||
nsAutoAnimationMutationBatch::sCurrentBatch = nullptr;
|
||||
|
||||
void
|
||||
nsAutoAnimationMutationBatch::Done()
|
||||
{
|
||||
if (sCurrentBatch != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
sCurrentBatch = mPreviousBatch;
|
||||
if (mObservers.IsEmpty()) {
|
||||
nsDOMMutationObserver::LeaveMutationHandling();
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
for (nsDOMMutationObserver* ob : mObservers) {
|
||||
nsRefPtr<nsDOMMutationRecord> m =
|
||||
new nsDOMMutationRecord(nsGkAtoms::animations, ob->GetParentObject());
|
||||
m->mTarget = mBatchTarget;
|
||||
|
||||
for (const Entry& e : mEntries) {
|
||||
if (e.mState == eState_Added) {
|
||||
m->mAddedAnimations.AppendElement(e.mPlayer);
|
||||
} else if (e.mState == eState_Removed) {
|
||||
m->mRemovedAnimations.AppendElement(e.mPlayer);
|
||||
} else if (e.mState == eState_RemainedPresent && e.mChanged) {
|
||||
m->mChangedAnimations.AppendElement(e.mPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m->mAddedAnimations.IsEmpty() ||
|
||||
!m->mChangedAnimations.IsEmpty() ||
|
||||
!m->mRemovedAnimations.IsEmpty()) {
|
||||
ob->AppendMutationRecord(m.forget());
|
||||
ob->ScheduleForRun();
|
||||
}
|
||||
}
|
||||
nsDOMMutationObserver::LeaveMutationHandling();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsStubMutationObserver.h"
|
||||
#include "nsStubAnimationObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/MutationObserverBinding.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/dom/AnimationPlayer.h"
|
||||
#include "nsIAnimationObserver.h"
|
||||
|
||||
class nsDOMMutationObserver;
|
||||
using mozilla::dom::MutationObservingInfo;
|
||||
@@ -34,6 +36,8 @@ class nsDOMMutationRecord final : public nsISupports,
|
||||
virtual ~nsDOMMutationRecord() {}
|
||||
|
||||
public:
|
||||
typedef nsTArray<nsRefPtr<mozilla::dom::AnimationPlayer>> AnimationPlayerArray;
|
||||
|
||||
nsDOMMutationRecord(nsIAtom* aType, nsISupports* aOwner)
|
||||
: mType(aType), mAttrNamespace(NullString()), mPrevValue(NullString()), mOwner(aOwner)
|
||||
{
|
||||
@@ -91,6 +95,21 @@ public:
|
||||
aRetVal.SetOwnedString(mPrevValue);
|
||||
}
|
||||
|
||||
void GetAddedAnimations(AnimationPlayerArray& aRetVal) const
|
||||
{
|
||||
aRetVal = mAddedAnimations;
|
||||
}
|
||||
|
||||
void GetRemovedAnimations(AnimationPlayerArray& aRetVal) const
|
||||
{
|
||||
aRetVal = mRemovedAnimations;
|
||||
}
|
||||
|
||||
void GetChangedAnimations(AnimationPlayerArray& aRetVal) const
|
||||
{
|
||||
aRetVal = mChangedAnimations;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> mTarget;
|
||||
nsCOMPtr<nsIAtom> mType;
|
||||
nsCOMPtr<nsIAtom> mAttrName;
|
||||
@@ -100,6 +119,9 @@ public:
|
||||
nsRefPtr<nsSimpleContentList> mRemovedNodes;
|
||||
nsCOMPtr<nsINode> mPreviousSibling;
|
||||
nsCOMPtr<nsINode> mNextSibling;
|
||||
AnimationPlayerArray mAddedAnimations;
|
||||
AnimationPlayerArray mRemovedAnimations;
|
||||
AnimationPlayerArray mChangedAnimations;
|
||||
|
||||
nsRefPtr<nsDOMMutationRecord> mNext;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
@@ -107,7 +129,7 @@ public:
|
||||
|
||||
// Base class just prevents direct access to
|
||||
// members to make sure we go through getters/setters.
|
||||
class nsMutationReceiverBase : public nsStubMutationObserver
|
||||
class nsMutationReceiverBase : public nsStubAnimationObserver
|
||||
{
|
||||
public:
|
||||
virtual ~nsMutationReceiverBase() { }
|
||||
@@ -168,6 +190,13 @@ public:
|
||||
mAllAttributes = aAll;
|
||||
}
|
||||
|
||||
bool Animations() { return mParent ? mParent->Animations() : mAnimations; }
|
||||
void SetAnimations(bool aAnimations)
|
||||
{
|
||||
NS_ASSERTION(!mParent, "Shouldn't have parent");
|
||||
mAnimations = aAnimations;
|
||||
}
|
||||
|
||||
bool AttributeOldValue() {
|
||||
return mParent ? mParent->AttributeOldValue()
|
||||
: mAttributeOldValue;
|
||||
@@ -200,9 +229,6 @@ protected:
|
||||
nsMutationReceiverBase(nsINode* aTarget, nsDOMMutationObserver* aObserver)
|
||||
: mTarget(aTarget), mObserver(aObserver), mRegisterTarget(aTarget)
|
||||
{
|
||||
mRegisterTarget->AddMutationObserver(this);
|
||||
mRegisterTarget->SetMayHaveDOMMutationObserver();
|
||||
mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
|
||||
}
|
||||
|
||||
nsMutationReceiverBase(nsINode* aRegisterTarget,
|
||||
@@ -211,7 +237,13 @@ protected:
|
||||
mRegisterTarget(aRegisterTarget), mKungFuDeathGrip(aParent->Target())
|
||||
{
|
||||
NS_ASSERTION(mParent->Subtree(), "Should clone a non-subtree observer!");
|
||||
mRegisterTarget->AddMutationObserver(this);
|
||||
}
|
||||
|
||||
virtual void AddMutationObserver() = 0;
|
||||
|
||||
void AddObserver()
|
||||
{
|
||||
AddMutationObserver();
|
||||
mRegisterTarget->SetMayHaveDOMMutationObserver();
|
||||
mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
|
||||
}
|
||||
@@ -263,6 +295,7 @@ private:
|
||||
bool mAttributes;
|
||||
bool mAllAttributes;
|
||||
bool mAttributeOldValue;
|
||||
bool mAnimations;
|
||||
nsCOMArray<nsIAtom> mAttributeFilter;
|
||||
};
|
||||
|
||||
@@ -273,14 +306,20 @@ protected:
|
||||
virtual ~nsMutationReceiver() { Disconnect(false); }
|
||||
|
||||
public:
|
||||
nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
|
||||
|
||||
nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
|
||||
: nsMutationReceiverBase(aRegisterTarget, aParent)
|
||||
static nsMutationReceiver* Create(nsINode* aTarget,
|
||||
nsDOMMutationObserver* aObserver)
|
||||
{
|
||||
NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
|
||||
"Shouldn't create deep observer hierarchies!");
|
||||
aParent->AddClone(this);
|
||||
nsMutationReceiver* r = new nsMutationReceiver(aTarget, aObserver);
|
||||
r->AddObserver();
|
||||
return r;
|
||||
}
|
||||
|
||||
static nsMutationReceiver* Create(nsINode* aRegisterTarget,
|
||||
nsMutationReceiverBase* aParent)
|
||||
{
|
||||
nsMutationReceiver* r = new nsMutationReceiver(aRegisterTarget, aParent);
|
||||
r->AddObserver();
|
||||
return r;
|
||||
}
|
||||
|
||||
nsMutationReceiver* GetParent()
|
||||
@@ -331,6 +370,72 @@ public:
|
||||
AttributeWillChange(aDocument, aElement, aNameSpaceID, aAttribute,
|
||||
nsIDOMMutationEvent::MODIFICATION);
|
||||
}
|
||||
|
||||
protected:
|
||||
nsMutationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver);
|
||||
|
||||
nsMutationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
|
||||
: nsMutationReceiverBase(aRegisterTarget, aParent)
|
||||
{
|
||||
NS_ASSERTION(!static_cast<nsMutationReceiver*>(aParent)->GetParent(),
|
||||
"Shouldn't create deep observer hierarchies!");
|
||||
aParent->AddClone(this);
|
||||
}
|
||||
|
||||
virtual void AddMutationObserver() override
|
||||
{
|
||||
mRegisterTarget->AddMutationObserver(this);
|
||||
}
|
||||
};
|
||||
|
||||
class nsAnimationReceiver : public nsMutationReceiver
|
||||
{
|
||||
public:
|
||||
static nsAnimationReceiver* Create(nsINode* aTarget,
|
||||
nsDOMMutationObserver* aObserver)
|
||||
{
|
||||
nsAnimationReceiver* r = new nsAnimationReceiver(aTarget, aObserver);
|
||||
r->AddObserver();
|
||||
return r;
|
||||
}
|
||||
|
||||
static nsAnimationReceiver* Create(nsINode* aRegisterTarget,
|
||||
nsMutationReceiverBase* aParent)
|
||||
{
|
||||
nsAnimationReceiver* r = new nsAnimationReceiver(aRegisterTarget, aParent);
|
||||
r->AddObserver();
|
||||
return r;
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED
|
||||
|
||||
protected:
|
||||
virtual ~nsAnimationReceiver() {}
|
||||
|
||||
nsAnimationReceiver(nsINode* aTarget, nsDOMMutationObserver* aObserver)
|
||||
: nsMutationReceiver(aTarget, aObserver) {}
|
||||
|
||||
nsAnimationReceiver(nsINode* aRegisterTarget, nsMutationReceiverBase* aParent)
|
||||
: nsMutationReceiver(aRegisterTarget, aParent) {}
|
||||
|
||||
virtual void AddMutationObserver() override
|
||||
{
|
||||
mRegisterTarget->AddAnimationObserver(this);
|
||||
}
|
||||
|
||||
private:
|
||||
enum AnimationMutation {
|
||||
eAnimationMutation_Added,
|
||||
eAnimationMutation_Changed,
|
||||
eAnimationMutation_Removed
|
||||
};
|
||||
|
||||
void RecordAnimationMutation(mozilla::dom::AnimationPlayer* aPlayer,
|
||||
AnimationMutation aMutationType);
|
||||
};
|
||||
|
||||
#define NS_DOM_MUTATION_OBSERVER_IID \
|
||||
@@ -419,8 +524,12 @@ protected:
|
||||
virtual ~nsDOMMutationObserver();
|
||||
|
||||
friend class nsMutationReceiver;
|
||||
friend class nsAnimationReceiver;
|
||||
friend class nsAutoMutationBatch;
|
||||
nsMutationReceiver* GetReceiverFor(nsINode* aNode, bool aMayCreate);
|
||||
friend class nsAutoAnimationMutationBatch;
|
||||
nsMutationReceiver* GetReceiverFor(nsINode* aNode,
|
||||
bool aMayCreate,
|
||||
bool aWantsAnimations);
|
||||
void RemoveReceiver(nsMutationReceiver* aReceiver);
|
||||
|
||||
already_AddRefed<nsIVariant> TakeRecords();
|
||||
@@ -596,6 +705,156 @@ private:
|
||||
nsCOMPtr<nsINode> mNextSibling;
|
||||
};
|
||||
|
||||
class nsAutoAnimationMutationBatch
|
||||
{
|
||||
struct Entry;
|
||||
|
||||
public:
|
||||
explicit nsAutoAnimationMutationBatch(nsINode* aTarget)
|
||||
: mBatchTarget(nullptr)
|
||||
{
|
||||
Init(aTarget);
|
||||
}
|
||||
|
||||
void Init(nsINode* aTarget)
|
||||
{
|
||||
if (aTarget && aTarget->OwnerDoc()->MayHaveDOMMutationObservers()) {
|
||||
mBatchTarget = aTarget;
|
||||
mPreviousBatch = sCurrentBatch;
|
||||
sCurrentBatch = this;
|
||||
nsDOMMutationObserver::EnterMutationHandling();
|
||||
}
|
||||
}
|
||||
|
||||
~nsAutoAnimationMutationBatch()
|
||||
{
|
||||
Done();
|
||||
}
|
||||
|
||||
void Done();
|
||||
|
||||
static bool IsBatching()
|
||||
{
|
||||
return !!sCurrentBatch;
|
||||
}
|
||||
|
||||
static nsAutoAnimationMutationBatch* GetCurrentBatch()
|
||||
{
|
||||
return sCurrentBatch;
|
||||
}
|
||||
|
||||
static void AddObserver(nsDOMMutationObserver* aObserver)
|
||||
{
|
||||
if (sCurrentBatch->mObservers.Contains(aObserver)) {
|
||||
return;
|
||||
}
|
||||
sCurrentBatch->mObservers.AppendElement(aObserver);
|
||||
}
|
||||
|
||||
static nsINode* GetBatchTarget()
|
||||
{
|
||||
return sCurrentBatch->mBatchTarget;
|
||||
}
|
||||
|
||||
static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer)
|
||||
{
|
||||
if (!IsBatching()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
|
||||
if (entry) {
|
||||
switch (entry->mState) {
|
||||
case eState_RemainedAbsent:
|
||||
entry->mState = eState_Added;
|
||||
break;
|
||||
case eState_Removed:
|
||||
entry->mState = eState_RemainedPresent;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("shouldn't have observed an animation being added "
|
||||
"twice");
|
||||
}
|
||||
} else {
|
||||
entry = sCurrentBatch->mEntries.AppendElement();
|
||||
entry->mPlayer = aPlayer;
|
||||
entry->mState = eState_Added;
|
||||
entry->mChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer)
|
||||
{
|
||||
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
|
||||
if (entry) {
|
||||
NS_ASSERTION(entry->mState == eState_RemainedPresent ||
|
||||
entry->mState == eState_Added,
|
||||
"shouldn't have observed an animation being changed after "
|
||||
"being removed");
|
||||
entry->mChanged = true;
|
||||
} else {
|
||||
entry = sCurrentBatch->mEntries.AppendElement();
|
||||
entry->mPlayer = aPlayer;
|
||||
entry->mState = eState_RemainedPresent;
|
||||
entry->mChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer)
|
||||
{
|
||||
Entry* entry = sCurrentBatch->FindEntry(aPlayer);
|
||||
if (entry) {
|
||||
switch (entry->mState) {
|
||||
case eState_RemainedPresent:
|
||||
entry->mState = eState_Removed;
|
||||
break;
|
||||
case eState_Added:
|
||||
entry->mState = eState_RemainedAbsent;
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("shouldn't have observed an animation being removed "
|
||||
"twice");
|
||||
}
|
||||
} else {
|
||||
entry = sCurrentBatch->mEntries.AppendElement();
|
||||
entry->mPlayer = aPlayer;
|
||||
entry->mState = eState_Removed;
|
||||
entry->mChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* FindEntry(mozilla::dom::AnimationPlayer* aPlayer)
|
||||
{
|
||||
for (Entry& e : mEntries) {
|
||||
if (e.mPlayer == aPlayer) {
|
||||
return &e;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
enum State {
|
||||
eState_RemainedPresent,
|
||||
eState_RemainedAbsent,
|
||||
eState_Added,
|
||||
eState_Removed
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
nsRefPtr<mozilla::dom::AnimationPlayer> mPlayer;
|
||||
State mState;
|
||||
bool mChanged;
|
||||
};
|
||||
|
||||
static nsAutoAnimationMutationBatch* sCurrentBatch;
|
||||
nsAutoAnimationMutationBatch* mPreviousBatch;
|
||||
nsAutoTArray<nsDOMMutationObserver*, 2> mObservers;
|
||||
nsTArray<Entry> mEntries;
|
||||
nsINode* mBatchTarget;
|
||||
};
|
||||
|
||||
inline
|
||||
nsDOMMutationObserver*
|
||||
nsMutationReceiverBase::Observer()
|
||||
|
||||
@@ -4767,7 +4767,6 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
||||
nsLoadFlags loadFlags = 0;
|
||||
channel->GetLoadFlags(&loadFlags);
|
||||
// If we are shift-reloaded, don't associate with a ServiceWorker.
|
||||
// FIXME(nsm): Bug 1041339.
|
||||
if (loadFlags & nsIRequest::LOAD_BYPASS_CACHE) {
|
||||
NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
|
||||
return;
|
||||
|
||||
@@ -1355,7 +1355,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
|
||||
nsCOMPtr<nsIDOMRange> range;
|
||||
nsCOMPtr<nsIDOMNode> commonParent;
|
||||
Selection* selection = static_cast<Selection*>(aSelection);
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
|
||||
// if selection is uninitialized return
|
||||
if (!rangeCount)
|
||||
|
||||
@@ -88,6 +88,7 @@ GK_ATOM(ancestor, "ancestor")
|
||||
GK_ATOM(ancestorOrSelf, "ancestor-or-self")
|
||||
GK_ATOM(anchor, "anchor")
|
||||
GK_ATOM(_and, "and")
|
||||
GK_ATOM(animations, "animations")
|
||||
GK_ATOM(anonid, "anonid")
|
||||
GK_ATOM(any, "any")
|
||||
GK_ATOM(mozapp, "mozapp")
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; 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/. */
|
||||
#ifndef nsIAnimationObserver_h___
|
||||
#define nsIAnimationObserver_h___
|
||||
|
||||
#include "nsIMutationObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class AnimationPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
#define NS_IANIMATION_OBSERVER_IID \
|
||||
{ 0xed025fc7, 0xdeda, 0x48b9, \
|
||||
{ 0x9c, 0x35, 0xf2, 0xb6, 0x1e, 0xeb, 0xd0, 0x8d } }
|
||||
|
||||
class nsIAnimationObserver : public nsIMutationObserver
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IANIMATION_OBSERVER_IID)
|
||||
|
||||
virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) = 0;
|
||||
virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) = 0;
|
||||
virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAnimationObserver, NS_IANIMATION_OBSERVER_IID)
|
||||
|
||||
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED \
|
||||
virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
override;
|
||||
|
||||
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED \
|
||||
virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
override;
|
||||
|
||||
#define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED \
|
||||
virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
override;
|
||||
|
||||
#define NS_IMPL_NSIANIMATIONOBSERVER_STUB(class_) \
|
||||
void \
|
||||
class_::AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
class_::AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
{ \
|
||||
} \
|
||||
void \
|
||||
class_::AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \
|
||||
{ \
|
||||
} \
|
||||
NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(class_) \
|
||||
NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(class_)
|
||||
|
||||
#define NS_DECL_NSIANIMATIONOBSERVER \
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED \
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED \
|
||||
NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED \
|
||||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
|
||||
#endif // nsIAnimationObserver_h___
|
||||
@@ -2252,6 +2252,16 @@ public:
|
||||
mMayHaveDOMMutationObservers = true;
|
||||
}
|
||||
|
||||
bool MayHaveAnimationObservers()
|
||||
{
|
||||
return mMayHaveAnimationObservers;
|
||||
}
|
||||
|
||||
void SetMayHaveAnimationObservers()
|
||||
{
|
||||
mMayHaveAnimationObservers = true;
|
||||
}
|
||||
|
||||
bool IsInSyncOperation()
|
||||
{
|
||||
return mInSyncOperationCount != 0;
|
||||
@@ -2764,6 +2774,9 @@ protected:
|
||||
// True if a DOMMutationObserver is perhaps attached to a node in the document.
|
||||
bool mMayHaveDOMMutationObservers;
|
||||
|
||||
// True if an nsIAnimationObserver is perhaps attached to a node in the document.
|
||||
bool mMayHaveAnimationObservers;
|
||||
|
||||
// True if a document has loaded Mixed Active Script (see nsMixedContentBlocker.cpp)
|
||||
bool mHasMixedActiveContentLoaded;
|
||||
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
#include "GeometryUtils.h"
|
||||
#include "nsIAnimationObserver.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@@ -2981,3 +2982,18 @@ nsINode::GetScopeChainParent() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsINode::AddAnimationObserver(nsIAnimationObserver* aAnimationObserver)
|
||||
{
|
||||
AddMutationObserver(aAnimationObserver);
|
||||
OwnerDoc()->SetMayHaveAnimationObservers();
|
||||
}
|
||||
|
||||
void
|
||||
nsINode::AddAnimationObserverUnlessExists(
|
||||
nsIAnimationObserver* aAnimationObserver)
|
||||
{
|
||||
AddMutationObserverUnlessExists(aAnimationObserver);
|
||||
OwnerDoc()->SetMayHaveAnimationObservers();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ class nsAttrAndChildArray;
|
||||
class nsChildContentList;
|
||||
struct nsCSSSelectorList;
|
||||
class nsDOMAttributeMap;
|
||||
class nsIAnimationObserver;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIDOMElement;
|
||||
@@ -955,6 +956,9 @@ public:
|
||||
* adding observers while inside a notification is not a good idea. An
|
||||
* observer that is already observing the node must not be added without
|
||||
* being removed first.
|
||||
*
|
||||
* For mutation observers that implement nsIAnimationObserver, use
|
||||
* AddAnimationObserver instead.
|
||||
*/
|
||||
void AddMutationObserver(nsIMutationObserver* aMutationObserver)
|
||||
{
|
||||
@@ -968,6 +972,9 @@ public:
|
||||
/**
|
||||
* Same as above, but only adds the observer if its not observing
|
||||
* the node already.
|
||||
*
|
||||
* For mutation observers that implement nsIAnimationObserver, use
|
||||
* AddAnimationObserverUnlessExists instead.
|
||||
*/
|
||||
void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver)
|
||||
{
|
||||
@@ -975,6 +982,20 @@ public:
|
||||
s->mMutationObservers.AppendElementUnlessExists(aMutationObserver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as AddMutationObserver, but for nsIAnimationObservers. This
|
||||
* additionally records on the document that animation observers have
|
||||
* been registered, which is used to determine whether notifications
|
||||
* must be fired when animations are added, removed or changed.
|
||||
*/
|
||||
void AddAnimationObserver(nsIAnimationObserver* aAnimationObserver);
|
||||
|
||||
/**
|
||||
* Same as above, but only adds the observer if its not observing
|
||||
* the node already.
|
||||
*/
|
||||
void AddAnimationObserverUnlessExists(nsIAnimationObserver* aAnimationObserver);
|
||||
|
||||
/**
|
||||
* Removes a mutation observer.
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,34 @@ using mozilla::AutoJSContext;
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
#define IMPL_ANIMATION_NOTIFICATION(func_, content_, params_) \
|
||||
PR_BEGIN_MACRO \
|
||||
bool needsEnterLeave = doc->MayHaveDOMMutationObservers(); \
|
||||
if (needsEnterLeave) { \
|
||||
nsDOMMutationObserver::EnterMutationHandling(); \
|
||||
} \
|
||||
nsINode* node = content_; \
|
||||
do { \
|
||||
nsINode::nsSlots* slots = node->GetExistingSlots(); \
|
||||
if (slots && !slots->mMutationObservers.IsEmpty()) { \
|
||||
/* No need to explicitly notify the first observer first \
|
||||
since that'll happen anyway. */ \
|
||||
NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI( \
|
||||
slots->mMutationObservers, nsIMutationObserver, \
|
||||
nsIAnimationObserver, func_, params_); \
|
||||
} \
|
||||
ShadowRoot* shadow = ShadowRoot::FromNode(node); \
|
||||
if (shadow) { \
|
||||
node = shadow->GetPoolHost(); \
|
||||
} else { \
|
||||
node = node->GetParentNode(); \
|
||||
} \
|
||||
} while (node); \
|
||||
if (needsEnterLeave) { \
|
||||
nsDOMMutationObserver::LeaveMutationHandling(); \
|
||||
} \
|
||||
PR_END_MACRO
|
||||
|
||||
void
|
||||
nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
|
||||
CharacterDataChangeInfo* aInfo)
|
||||
@@ -185,6 +213,70 @@ nsNodeUtils::ContentRemoved(nsINode* aContainer,
|
||||
aPreviousSibling));
|
||||
}
|
||||
|
||||
static inline Element*
|
||||
GetTarget(AnimationPlayer* aPlayer)
|
||||
{
|
||||
Animation* source = aPlayer->GetSource();
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element* target;
|
||||
nsCSSPseudoElements::Type pseudoType;
|
||||
source->GetTarget(target, pseudoType);
|
||||
|
||||
// If the animation targets a pseudo-element, we don't dispatch
|
||||
// notifications for it. (In the future we will have PseudoElement
|
||||
// objects we can use as the target of the notifications.)
|
||||
if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return source->GetTarget();
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::AnimationAdded(AnimationPlayer* aPlayer)
|
||||
{
|
||||
Element* target = GetTarget(aPlayer);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
nsIDocument* doc = target->OwnerDoc();
|
||||
|
||||
if (doc->MayHaveAnimationObservers()) {
|
||||
IMPL_ANIMATION_NOTIFICATION(AnimationAdded, target, (aPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::AnimationChanged(AnimationPlayer* aPlayer)
|
||||
{
|
||||
Element* target = GetTarget(aPlayer);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
nsIDocument* doc = target->OwnerDoc();
|
||||
|
||||
if (doc->MayHaveAnimationObservers()) {
|
||||
IMPL_ANIMATION_NOTIFICATION(AnimationChanged, target, (aPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::AnimationRemoved(AnimationPlayer* aPlayer)
|
||||
{
|
||||
Element* target = GetTarget(aPlayer);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
nsIDocument* doc = target->OwnerDoc();
|
||||
|
||||
if (doc->MayHaveAnimationObservers()) {
|
||||
IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, target, (aPlayer));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsNodeUtils::LastRelease(nsINode* aNode)
|
||||
{
|
||||
@@ -457,6 +549,10 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
|
||||
newDoc->SetMayHaveDOMMutationObservers();
|
||||
}
|
||||
|
||||
if (oldDoc != newDoc && oldDoc->MayHaveAnimationObservers()) {
|
||||
newDoc->SetMayHaveAnimationObservers();
|
||||
}
|
||||
|
||||
if (elem) {
|
||||
elem->RecompileScriptEventListeners();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ class nsIVariant;
|
||||
class nsIDOMNode;
|
||||
template<class E> class nsCOMArray;
|
||||
class nsCycleCollectionTraversalCallback;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class AnimationPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
class nsNodeUtils
|
||||
{
|
||||
@@ -122,6 +127,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer);
|
||||
static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer);
|
||||
static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer);
|
||||
|
||||
/**
|
||||
* To be called when reference count of aNode drops to zero.
|
||||
* @param aNode The node which is going to be deleted.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#include "nsStubAnimationObserver.h"
|
||||
|
||||
NS_IMPL_NSIANIMATIONOBSERVER_STUB(nsStubAnimationObserver)
|
||||
@@ -0,0 +1,16 @@
|
||||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef nsStubAnimationObserver_h_
|
||||
#define nsStubAnimationObserver_h_
|
||||
|
||||
#include "nsIAnimationObserver.h"
|
||||
|
||||
class nsStubAnimationObserver : public nsIAnimationObserver {
|
||||
public:
|
||||
NS_DECL_NSIANIMATIONOBSERVER
|
||||
};
|
||||
|
||||
#endif // !defined(nsStubAnimationObserver_h_)
|
||||
@@ -5,21 +5,35 @@
|
||||
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIURI;
|
||||
|
||||
[builtinclass, uuid(d4367ffe-e435-4195-95f8-0a51b1bbfdfb)]
|
||||
[scriptable, uuid(52ee2c9d-ee87-4caf-9588-23ae77ff8798)]
|
||||
interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||
{
|
||||
// aState is true if the unregistration succeded.
|
||||
// It's false if this ServiceWorkerRegistration doesn't exist.
|
||||
[noscript] void UnregisterSucceeded(in bool aState);
|
||||
[noscript] void UnregisterFailed();
|
||||
void unregisterSucceeded(in bool aState);
|
||||
void unregisterFailed();
|
||||
};
|
||||
|
||||
[builtinclass, uuid(e4c8baa5-237a-4bf6-82d4-ea06eb4b76ba)]
|
||||
[scriptable, builtinclass, uuid(8ce0d197-5740-4ddf-aa4a-e5a63e611d03)]
|
||||
interface nsIServiceWorkerInfo : nsISupports
|
||||
{
|
||||
readonly attribute nsIPrincipal principal;
|
||||
|
||||
readonly attribute DOMString scope;
|
||||
readonly attribute DOMString scriptSpec;
|
||||
readonly attribute DOMString currentWorkerURL;
|
||||
|
||||
readonly attribute DOMString activeCacheName;
|
||||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -103,6 +117,10 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
|
||||
// Testing
|
||||
DOMString getScopeForUrl(in DOMString path);
|
||||
|
||||
// This is meant to be used only by about:serviceworkers. It returns an array
|
||||
// of nsIServiceWorkerInfo.
|
||||
nsIArray getAllRegistrations();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
||||
@@ -2779,6 +2779,9 @@ NS_EXPORT void
|
||||
AfterNuwaFork()
|
||||
{
|
||||
SetCurrentProcessPrivileges(base::PRIVILEGES_DEFAULT);
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxEarlyInit(XRE_GetProcessType(), /* isNuwa: */ false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MOZ_NUWA_PROCESS
|
||||
|
||||
+5
-1
@@ -74,7 +74,6 @@ DIRS += [
|
||||
'notification',
|
||||
'offline',
|
||||
'power',
|
||||
'push',
|
||||
'quota',
|
||||
'security',
|
||||
'settings',
|
||||
@@ -136,6 +135,11 @@ if CONFIG['MOZ_GAMEPAD']:
|
||||
if CONFIG['MOZ_NFC']:
|
||||
DIRS += ['nfc']
|
||||
|
||||
if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
DIRS += ['simplepush']
|
||||
else:
|
||||
DIRS += ['push']
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
DIRS += ['secureelement']
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Don't modify this, instead set services.push.debug.
|
||||
let gDebuggingEnabled = false;
|
||||
|
||||
function debug(s) {
|
||||
if (gDebuggingEnabled)
|
||||
dump("-*- Push.js: " + s + "\n");
|
||||
}
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
const PUSH_CID = Components.ID("{cde1d019-fad8-4044-b141-65fb4fb7a245}");
|
||||
|
||||
/**
|
||||
* The Push component runs in the child process and exposes the SimplePush API
|
||||
* to the web application. The PushService running in the parent process is the
|
||||
* one actually performing all operations.
|
||||
*/
|
||||
function Push() {
|
||||
debug("Push Constructor");
|
||||
}
|
||||
|
||||
Push.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
contractID: "@mozilla.org/push/PushManager;1",
|
||||
|
||||
classID : PUSH_CID,
|
||||
|
||||
QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsIObserver]),
|
||||
|
||||
init: function(aWindow) {
|
||||
// Set debug first so that all debugging actually works.
|
||||
// NOTE: We don't add an observer here like in PushService. Flipping the
|
||||
// pref will require a reload of the app/page, which seems acceptable.
|
||||
gDebuggingEnabled = Services.prefs.getBoolPref("services.push.debug");
|
||||
debug("init()");
|
||||
|
||||
let principal = aWindow.document.nodePrincipal;
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"]
|
||||
.getService(Ci.nsIAppsService);
|
||||
|
||||
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
|
||||
this._pageURL = principal.URI;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [
|
||||
"PushService:Register:OK",
|
||||
"PushService:Register:KO",
|
||||
"PushService:Unregister:OK",
|
||||
"PushService:Unregister:KO",
|
||||
"PushService:Registrations:OK",
|
||||
"PushService:Registrations:KO"
|
||||
]);
|
||||
|
||||
this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage()");
|
||||
let request = this.getRequest(aMessage.data.requestID);
|
||||
let json = aMessage.data;
|
||||
if (!request) {
|
||||
debug("No request " + json.requestID);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "PushService:Register:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
break;
|
||||
case "PushService:Register:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
case "PushService:Unregister:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.pushEndpoint);
|
||||
break;
|
||||
case "PushService:Unregister:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
case "PushService:Registrations:OK":
|
||||
Services.DOMRequest.fireSuccess(request, json.registrations);
|
||||
break;
|
||||
case "PushService:Registrations:KO":
|
||||
Services.DOMRequest.fireError(request, json.error);
|
||||
break;
|
||||
default:
|
||||
debug("NOT IMPLEMENTED! receiveMessage for " + aMessage.name);
|
||||
}
|
||||
},
|
||||
|
||||
register: function() {
|
||||
debug("register()");
|
||||
let req = this.createRequest();
|
||||
if (!Services.prefs.getBoolPref("services.push.connection.enabled")) {
|
||||
// If push socket is disabled by the user, immediately error rather than
|
||||
// timing out.
|
||||
Services.DOMRequest.fireErrorAsync(req, "NetworkError");
|
||||
return req;
|
||||
}
|
||||
|
||||
this._cpmm.sendAsyncMessage("Push:Register", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
},
|
||||
|
||||
unregister: function(aPushEndpoint) {
|
||||
debug("unregister(" + aPushEndpoint + ")");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Unregister", {
|
||||
pageURL: this._pageURL.spec,
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req),
|
||||
pushEndpoint: aPushEndpoint
|
||||
});
|
||||
return req;
|
||||
},
|
||||
|
||||
registrations: function() {
|
||||
debug("registrations()");
|
||||
let req = this.createRequest();
|
||||
this._cpmm.sendAsyncMessage("Push:Registrations", {
|
||||
manifestURL: this._manifestURL,
|
||||
requestID: this.getRequestId(req)
|
||||
});
|
||||
return req;
|
||||
}
|
||||
}
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);
|
||||
@@ -0,0 +1,8 @@
|
||||
# DOM API
|
||||
component {cde1d019-fad8-4044-b141-65fb4fb7a245} Push.js
|
||||
contract @mozilla.org/push/PushManager;1 {cde1d019-fad8-4044-b141-65fb4fb7a245}
|
||||
|
||||
# Component to initialize PushService on startup.
|
||||
component {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d} PushServiceLauncher.js
|
||||
contract @mozilla.org/push/ServiceLauncher;1 {4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}
|
||||
category app-startup PushServiceLauncher @mozilla.org/push/ServiceLauncher;1
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function PushServiceLauncher() {
|
||||
};
|
||||
|
||||
PushServiceLauncher.prototype = {
|
||||
classID: Components.ID("{4b8caa3b-3c58-4f3c-a7f5-7bd9cb24c11d}"),
|
||||
|
||||
contractID: "@mozilla.org/push/ServiceLauncher;1",
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
observe: function observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "app-startup":
|
||||
Services.obs.addObserver(this, "final-ui-startup", true);
|
||||
break;
|
||||
case "final-ui-startup":
|
||||
Services.obs.removeObserver(this, "final-ui-startup");
|
||||
if (!Services.prefs.getBoolPref("services.push.enabled")) {
|
||||
return;
|
||||
}
|
||||
Cu.import("resource://gre/modules/PushService.jsm");
|
||||
PushService.init();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PushServiceLauncher]);
|
||||
@@ -0,0 +1,14 @@
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'Push.js',
|
||||
'Push.manifest',
|
||||
'PushServiceLauncher.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'PushService.jsm',
|
||||
]
|
||||
@@ -6,6 +6,9 @@
|
||||
#ifndef NS_SMILKEYSPLINE_H_
|
||||
#define NS_SMILKEYSPLINE_H_
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
/**
|
||||
* Utility class to provide scaling defined in a keySplines element.
|
||||
*/
|
||||
@@ -44,6 +47,16 @@ public:
|
||||
|
||||
void GetSplineDerivativeValues(double aX, double& aDX, double& aDY) const;
|
||||
|
||||
bool operator==(const nsSMILKeySpline& aOther) const {
|
||||
return mX1 == aOther.mX1 &&
|
||||
mY1 == aOther.mY1 &&
|
||||
mX2 == aOther.mX2 &&
|
||||
mY2 == aOther.mY2;
|
||||
}
|
||||
bool operator!=(const nsSMILKeySpline& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
CalcSampleValues();
|
||||
|
||||
@@ -28,6 +28,12 @@ interface MutationRecord {
|
||||
readonly attribute DOMString? attributeNamespace;
|
||||
[Constant]
|
||||
readonly attribute DOMString? oldValue;
|
||||
[Constant,Cached,ChromeOnly]
|
||||
readonly attribute sequence<AnimationPlayer> addedAnimations;
|
||||
[Constant,Cached,ChromeOnly]
|
||||
readonly attribute sequence<AnimationPlayer> changedAnimations;
|
||||
[Constant,Cached,ChromeOnly]
|
||||
readonly attribute sequence<AnimationPlayer> removedAnimations;
|
||||
};
|
||||
|
||||
[Constructor(MutationCallback mutationCallback)]
|
||||
@@ -52,6 +58,8 @@ dictionary MutationObserverInit {
|
||||
boolean subtree = false;
|
||||
boolean attributeOldValue;
|
||||
boolean characterDataOldValue;
|
||||
// [ChromeOnly]
|
||||
boolean animations;
|
||||
sequence<DOMString> attributeFilter;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/* -*- 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/.
|
||||
*/
|
||||
|
||||
[NavigatorProperty="push",
|
||||
JSImplementation="@mozilla.org/push/PushManager;1",
|
||||
CheckPermissions="push",
|
||||
Pref="services.push.enabled"]
|
||||
interface PushManager {
|
||||
DOMRequest register();
|
||||
DOMRequest unregister(DOMString pushEndpoint);
|
||||
DOMRequest registrations();
|
||||
};
|
||||
@@ -346,7 +346,6 @@ WEBIDL_FILES = [
|
||||
'ProfileTimelineMarker.webidl',
|
||||
'Promise.webidl',
|
||||
'PromiseDebugging.webidl',
|
||||
'PushManager.webidl',
|
||||
'RadioNodeList.webidl',
|
||||
'Range.webidl',
|
||||
'Rect.webidl',
|
||||
@@ -659,6 +658,12 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
'MozIccManager.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SIMPLEPUSH']:
|
||||
WEBIDL_FILES += SimplePushManager.webidl
|
||||
else:
|
||||
WEBIDL_FILES += [
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_NFC']:
|
||||
WEBIDL_FILES += [
|
||||
'MozIsoDepTech.webidl',
|
||||
|
||||
@@ -306,6 +306,6 @@ ServiceWorkerClients::Claim()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsScriptLoader.h"
|
||||
#include "nsDebug.h"
|
||||
@@ -1613,7 +1614,7 @@ private:
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
if (!swm->mServiceWorkerRegistrationInfos.Get(mScope, getter_AddRefs(registration))) {
|
||||
// "If registration is null, then, resolve promise with false."
|
||||
return mCallback->UnregisterSucceeded(false);
|
||||
return mCallback ? mCallback->UnregisterSucceeded(false) : NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(registration);
|
||||
@@ -1621,7 +1622,7 @@ private:
|
||||
// "Set registration's uninstalling flag."
|
||||
registration->mPendingUninstall = true;
|
||||
// "Resolve promise with true"
|
||||
nsresult rv = mCallback->UnregisterSucceeded(true);
|
||||
nsresult rv = mCallback ? mCallback->UnregisterSucceeded(true) : NS_OK;
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
@@ -1659,8 +1660,10 @@ ServiceWorkerManager::Unregister(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aScope)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCallback);
|
||||
|
||||
if (!aPrincipal) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// This is not accessible by content, and callers should always ensure scope is
|
||||
// a correct URI, so this is wrapped in DEBUG
|
||||
@@ -2812,6 +2815,130 @@ ServiceWorkerManager::RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistr
|
||||
mActor->SendUnregisterServiceWorker(principalInfo, NS_ConvertUTF8toUTF16(reg->mScope));
|
||||
}
|
||||
|
||||
class ServiceWorkerDataInfo final : public nsIServiceWorkerInfo
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISERVICEWORKERINFO
|
||||
|
||||
static already_AddRefed<ServiceWorkerDataInfo>
|
||||
Create(const ServiceWorkerRegistrationData& aData);
|
||||
|
||||
private:
|
||||
ServiceWorkerDataInfo()
|
||||
{}
|
||||
|
||||
~ServiceWorkerDataInfo()
|
||||
{}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsString mScope;
|
||||
nsString mScriptSpec;
|
||||
nsString mCurrentWorkerURL;
|
||||
nsString mActiveCacheName;
|
||||
nsString mWaitingCacheName;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ServiceWorkerDataInfo, nsIServiceWorkerInfo)
|
||||
|
||||
/* static */ already_AddRefed<ServiceWorkerDataInfo>
|
||||
ServiceWorkerDataInfo::Create(const ServiceWorkerRegistrationData& aData)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsRefPtr<ServiceWorkerDataInfo> info = new ServiceWorkerDataInfo();
|
||||
|
||||
info->mPrincipal = PrincipalInfoToPrincipal(aData.principal());
|
||||
if (!info->mPrincipal) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CopyUTF8toUTF16(aData.scope(), info->mScope);
|
||||
CopyUTF8toUTF16(aData.scriptSpec(), info->mScriptSpec);
|
||||
CopyUTF8toUTF16(aData.currentWorkerURL(), info->mCurrentWorkerURL);
|
||||
info->mActiveCacheName = aData.activeCacheName();
|
||||
info->mWaitingCacheName = aData.waitingCacheName();
|
||||
|
||||
return info.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetPrincipal(nsIPrincipal** aPrincipal)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
NS_ADDREF(*aPrincipal = mPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetScope(nsAString& aScope)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
aScope = mScope;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetScriptSpec(nsAString& aScriptSpec)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
aScriptSpec = mScriptSpec;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetCurrentWorkerURL(nsAString& aCurrentWorkerURL)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
aCurrentWorkerURL = mCurrentWorkerURL;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetActiveCacheName(nsAString& aActiveCacheName)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
aActiveCacheName = mActiveCacheName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerDataInfo::GetWaitingCacheName(nsAString& aWaitingCacheName)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
aWaitingCacheName = mWaitingCacheName;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetAllRegistrations(nsIArray** aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData> data;
|
||||
swr->GetRegistrations(data);
|
||||
|
||||
nsCOMPtr<nsIMutableArray> array(do_CreateInstance(NS_ARRAY_CONTRACTID));
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0, len = data.Length(); i < len; ++i) {
|
||||
nsCOMPtr<nsIServiceWorkerInfo> info = ServiceWorkerDataInfo::Create(data[i]);
|
||||
if (!info) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
array->AppendElement(info, false);
|
||||
}
|
||||
|
||||
array.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* 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 "ServiceWorkerPeriodicUpdater.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
||||
#define OBSERVER_TOPIC_IDLE_DAILY "idle-daily"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ServiceWorkerPeriodicUpdater, nsIObserver)
|
||||
|
||||
StaticRefPtr<ServiceWorkerPeriodicUpdater>
|
||||
ServiceWorkerPeriodicUpdater::sInstance;
|
||||
|
||||
already_AddRefed<ServiceWorkerPeriodicUpdater>
|
||||
ServiceWorkerPeriodicUpdater::GetSingleton()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
if (!sInstance) {
|
||||
sInstance = new ServiceWorkerPeriodicUpdater();
|
||||
ClearOnShutdown(&sInstance);
|
||||
}
|
||||
nsRefPtr<ServiceWorkerPeriodicUpdater> copy(sInstance.get());
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
ServiceWorkerPeriodicUpdater::ServiceWorkerPeriodicUpdater()
|
||||
{
|
||||
}
|
||||
|
||||
ServiceWorkerPeriodicUpdater::~ServiceWorkerPeriodicUpdater()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerPeriodicUpdater::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY) == 0) {
|
||||
// TODO: Update the service workers NOW!!!!!
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ServiceWorkerPeriodicUpdater_h
|
||||
#define mozilla_ServiceWorkerPeriodicUpdater_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class ServiceWorkerPeriodicUpdater final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static already_AddRefed<ServiceWorkerPeriodicUpdater> GetSingleton();
|
||||
|
||||
private:
|
||||
ServiceWorkerPeriodicUpdater();
|
||||
~ServiceWorkerPeriodicUpdater();
|
||||
|
||||
static StaticRefPtr<ServiceWorkerPeriodicUpdater> sInstance;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,7 @@ EXPORTS.mozilla.dom += [
|
||||
|
||||
EXPORTS.mozilla.dom.workers += [
|
||||
'ServiceWorkerManager.h',
|
||||
'ServiceWorkerPeriodicUpdater.h',
|
||||
'WorkerDebuggerManager.h',
|
||||
'Workers.h',
|
||||
]
|
||||
@@ -68,6 +69,7 @@ UNIFIED_SOURCES += [
|
||||
'ServiceWorkerContainer.cpp',
|
||||
'ServiceWorkerEvents.cpp',
|
||||
'ServiceWorkerManager.cpp',
|
||||
'ServiceWorkerPeriodicUpdater.cpp',
|
||||
'ServiceWorkerRegistrar.cpp',
|
||||
'ServiceWorkerRegistration.cpp',
|
||||
'ServiceWorkerScriptCache.cpp',
|
||||
|
||||
@@ -86,7 +86,7 @@ NS_IMETHODIMP TypeInState::NotifySelectionChanged(nsIDOMDocument *, nsISelection
|
||||
nsRefPtr<Selection> selection = static_cast<Selection*>(aSelection);
|
||||
|
||||
if (aSelection) {
|
||||
int32_t rangeCount = selection->GetRangeCount();
|
||||
int32_t rangeCount = selection->RangeCount();
|
||||
|
||||
if (selection->Collapsed() && rangeCount) {
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
|
||||
@@ -3606,7 +3606,7 @@ nsEditor::GetStartNodeAndOffset(Selection* aSelection, nsINode** aStartNode,
|
||||
*aStartNode = nullptr;
|
||||
*aStartOffset = 0;
|
||||
|
||||
NS_ENSURE_TRUE(aSelection->GetRangeCount(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(aSelection->RangeCount(), NS_ERROR_FAILURE);
|
||||
|
||||
const nsRange* range = aSelection->GetRangeAt(0);
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
@@ -3653,7 +3653,7 @@ nsEditor::GetEndNodeAndOffset(Selection* aSelection, nsINode** aEndNode,
|
||||
*aEndNode = nullptr;
|
||||
*aEndOffset = 0;
|
||||
|
||||
NS_ENSURE_TRUE(aSelection->GetRangeCount(), NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(aSelection->RangeCount(), NS_ERROR_FAILURE);
|
||||
|
||||
const nsRange* range = aSelection->GetRangeAt(0);
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
@@ -4207,7 +4207,7 @@ nsEditor::CreateTxnForDeleteSelection(EDirection aAction,
|
||||
// allocate the out-param transaction
|
||||
nsRefPtr<EditAggregateTxn> aggTxn = new EditAggregateTxn();
|
||||
|
||||
for (int32_t rangeIdx = 0; rangeIdx < selection->GetRangeCount(); ++rangeIdx) {
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < selection->RangeCount(); ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
NS_ENSURE_STATE(range);
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ nsHTMLEditRules::BeforeEdit(EditAction action,
|
||||
nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
|
||||
|
||||
// get the selection location
|
||||
NS_ENSURE_STATE(selection->GetRangeCount());
|
||||
NS_ENSURE_STATE(selection->RangeCount());
|
||||
mRangeItem->startNode = selection->GetRangeAt(0)->GetStartParent();
|
||||
mRangeItem->startOffset = selection->GetRangeAt(0)->StartOffset();
|
||||
mRangeItem->endNode = selection->GetRangeAt(0)->GetEndParent();
|
||||
@@ -582,7 +582,7 @@ nsHTMLEditRules::WillDoAction(Selection* aSelection,
|
||||
if (!aSelection) {
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ENSURE_TRUE(aSelection->GetRangeCount(), NS_OK);
|
||||
NS_ENSURE_TRUE(aSelection->RangeCount(), NS_OK);
|
||||
|
||||
nsRefPtr<nsRange> range = aSelection->GetRangeAt(0);
|
||||
nsCOMPtr<nsINode> selStartNode = range->GetStartParent();
|
||||
@@ -2427,7 +2427,7 @@ nsHTMLEditRules::WillDeleteSelection(Selection* aSelection,
|
||||
// except table elements.
|
||||
join = true;
|
||||
|
||||
uint32_t rangeCount = aSelection->GetRangeCount();
|
||||
uint32_t rangeCount = aSelection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = aSelection->GetRangeAt(rangeIdx);
|
||||
|
||||
@@ -6087,7 +6087,7 @@ nsHTMLEditRules::GetListActionNodes(nsCOMArray<nsIDOMNode> &outArrayOfNodes,
|
||||
// is only in part of it. used by list item dialog.
|
||||
if (aEntireList)
|
||||
{
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
nsCOMPtr<nsIDOMNode> commonParent, parent, tmp;
|
||||
@@ -7565,7 +7565,7 @@ nsHTMLEditRules::ReapplyCachedStyles()
|
||||
NS_ENSURE_STATE(mHTMLEditor);
|
||||
nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
|
||||
MOZ_ASSERT(selection);
|
||||
if (!selection->GetRangeCount()) {
|
||||
if (!selection->RangeCount()) {
|
||||
// Nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -8225,7 +8225,7 @@ nsHTMLEditRules::SelectionEndpointInNode(nsINode* aNode, bool* aResult)
|
||||
nsRefPtr<Selection> selection = mHTMLEditor->GetSelection();
|
||||
NS_ENSURE_STATE(selection);
|
||||
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
nsCOMPtr<nsIDOMNode> startParent, endParent;
|
||||
|
||||
@@ -3299,7 +3299,7 @@ nsHTMLEditor::GetIsSelectionEditable(bool* aIsSelectionEditable)
|
||||
// Per the editing spec as of June 2012: we have to have a selection whose
|
||||
// start and end nodes are editable, and which share an ancestor editing
|
||||
// host. (Bug 766387.)
|
||||
*aIsSelectionEditable = selection->GetRangeCount() &&
|
||||
*aIsSelectionEditable = selection->RangeCount() &&
|
||||
selection->GetAnchorNode()->IsEditable() &&
|
||||
selection->GetFocusNode()->IsEditable();
|
||||
|
||||
@@ -4571,7 +4571,7 @@ nsHTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
|
||||
{
|
||||
// loop thru the ranges in the selection
|
||||
nsAutoString bgcolor; bgcolor.AssignLiteral("bgcolor");
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsCOMPtr<nsIDOMNode> cachedBlockParent = nullptr;
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
|
||||
@@ -144,7 +144,7 @@ nsHTMLEditor::SetInlineProperty(nsIAtom *aProperty,
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (!cancel && !handled) {
|
||||
// loop thru the ranges in the selection
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
|
||||
@@ -1374,7 +1374,7 @@ nsresult nsHTMLEditor::RemoveInlinePropertyImpl(nsIAtom *aProperty, const nsAStr
|
||||
if (!cancel && !handled)
|
||||
{
|
||||
// loop thru the ranges in the selection
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
if (aProperty == nsGkAtoms::name) {
|
||||
@@ -1547,7 +1547,7 @@ nsHTMLEditor::RelativeFontChange( int32_t aSizeChange)
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(this);
|
||||
|
||||
// loop thru the ranges in the selection
|
||||
uint32_t rangeCount = selection->GetRangeCount();
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
|
||||
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ nsSelectionState::SaveSelection(Selection* aSel)
|
||||
{
|
||||
MOZ_ASSERT(aSel);
|
||||
int32_t arrayCount = mArray.Length();
|
||||
int32_t rangeCount = aSel->GetRangeCount();
|
||||
int32_t rangeCount = aSel->RangeCount();
|
||||
|
||||
// if we need more items in the array, new them
|
||||
if (arrayCount < rangeCount) {
|
||||
|
||||
@@ -2954,7 +2954,7 @@ nsHTMLEditor::GetNextSelectedCell(nsIDOMRange **aRange, nsIDOMElement **aCell)
|
||||
nsRefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
|
||||
int32_t rangeCount = selection->GetRangeCount();
|
||||
int32_t rangeCount = selection->RangeCount();
|
||||
|
||||
// Don't even try if index exceeds range count
|
||||
if (mSelectedCellIndex >= rangeCount)
|
||||
|
||||
@@ -1354,7 +1354,7 @@ mozInlineSpellChecker::DoSpellCheckSelection(mozInlineSpellWordUtil& aWordUtil,
|
||||
// elements inside the selection
|
||||
nsTArray<nsRefPtr<nsRange>> ranges;
|
||||
|
||||
int32_t count = aSpellCheckSelection->GetRangeCount();
|
||||
int32_t count = aSpellCheckSelection->RangeCount();
|
||||
|
||||
for (int32_t idx = 0; idx < count; idx++) {
|
||||
nsRange *range = aSpellCheckSelection->GetRangeAt(idx);
|
||||
@@ -1448,7 +1448,7 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
|
||||
// see if the selection has any ranges, if not, then we can optimize checking
|
||||
// range inclusion later (we have no ranges when we are initially checking or
|
||||
// when there are no misspelled words yet).
|
||||
int32_t originalRangeCount = aSpellCheckSelection->GetRangeCount();
|
||||
int32_t originalRangeCount = aSpellCheckSelection->RangeCount();
|
||||
|
||||
// set the starting DOM position to be the beginning of our range
|
||||
{
|
||||
@@ -1650,7 +1650,7 @@ mozInlineSpellChecker::ResumeCheck(mozInlineSpellStatus* aStatus)
|
||||
rv = mSpellCheck->GetCurrentDictionary(currentDictionary);
|
||||
if (NS_FAILED(rv)) {
|
||||
// no active dictionary
|
||||
int32_t count = spellCheckSelection->GetRangeCount();
|
||||
int32_t count = spellCheckSelection->RangeCount();
|
||||
for (int32_t index = count - 1; index >= 0; index--) {
|
||||
nsRange *checkRange = spellCheckSelection->GetRangeAt(index);
|
||||
if (checkRange) {
|
||||
@@ -1721,7 +1721,7 @@ mozInlineSpellChecker::CleanupRangesInSelection(Selection *aSelection)
|
||||
if (!aSelection)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int32_t count = aSelection->GetRangeCount();
|
||||
int32_t count = aSelection->RangeCount();
|
||||
|
||||
for (int32_t index = 0; index < count; index++)
|
||||
{
|
||||
|
||||
@@ -138,14 +138,18 @@ public:
|
||||
sink->Close();
|
||||
|
||||
RefPtr<ID2D1BitmapBrush> brush;
|
||||
rt->CreateBitmapBrush(mOldSurfBitmap, D2D1::BitmapBrushProperties(), D2D1::BrushProperties(), byRef(brush));
|
||||
HRESULT hr = rt->CreateBitmapBrush(mOldSurfBitmap, D2D1::BitmapBrushProperties(), D2D1::BrushProperties(), byRef(brush));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(false)) << "[D2D] CreateBitmapBrush failure " << hexa(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
rt->FillGeometry(invClippedArea, brush);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DrawTargetD2D *mDT;
|
||||
DrawTargetD2D *mDT;
|
||||
|
||||
// If we have an operator unbound by the source, this will contain a bitmap
|
||||
// with the old dest surface data.
|
||||
@@ -309,7 +313,12 @@ DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface,
|
||||
|
||||
D2D1_BITMAP_PROPERTIES props =
|
||||
D2D1::BitmapProperties(D2DPixelFormat(srcSurf->GetFormat()));
|
||||
mRT->CreateBitmap(D2D1::SizeU(UINT32(sourceRect.width), UINT32(sourceRect.height)), data, stride, props, byRef(bitmap));
|
||||
HRESULT hr = mRT->CreateBitmap(D2D1::SizeU(UINT32(sourceRect.width), UINT32(sourceRect.height)), data, stride, props, byRef(bitmap));
|
||||
if (FAILED(hr)) {
|
||||
IntSize size(sourceRect.width, sourceRect.height);
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(size))) << "[D2D] 1CreateBitmap failure " << size << " Code: " << hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// subtract the integer part leaving the fractional part
|
||||
aSource.x -= (uint32_t)aSource.x;
|
||||
@@ -2419,14 +2428,17 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mRT->CreateBitmapBrush(bitmap,
|
||||
|
||||
HRESULT hr = mRT->CreateBitmapBrush(bitmap,
|
||||
D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
|
||||
D2DExtend(pat->mExtendMode),
|
||||
D2DFilter(pat->mFilter)),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
byRef(bmBrush));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "[D2D] 1CreateBitmapBrush failure: " << hexa(hr);
|
||||
return nullptr;
|
||||
}
|
||||
return bmBrush.forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -841,7 +841,7 @@ DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
|
||||
hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mTempBitmap));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError() << "[D2D1.1] failed to create new TempBitmap " << aSize << " Code: " << hexa(hr);
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D2D1.1] failed to create new TempBitmap " << aSize << " Code: " << hexa(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1020,7 +1020,13 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
|
||||
}
|
||||
|
||||
RefPtr<ID2D1Bitmap> tmpBitmap;
|
||||
mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap));
|
||||
HRESULT hr = mDC->CreateBitmap(D2DIntSize(mSize), D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(tmpBitmap));
|
||||
if (FAILED(hr)) {
|
||||
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 5CreateBitmap failure " << mSize << " Code: " << hexa(hr);
|
||||
// For now, crash in this scenario; this should happen because tmpBitmap is
|
||||
// null and CopyFromBitmap call below dereferences it.
|
||||
// return;
|
||||
}
|
||||
|
||||
// This flush is important since the copy method will not know about the context drawing to the surface.
|
||||
// We also need to pop all the clips to make sure any drawn content will have made it to the final bitmap.
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
||||
'sha256.c',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] == 'Linux':
|
||||
if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] in ('Linux', 'Android'):
|
||||
USE_LIBS += [
|
||||
'mozsandbox',
|
||||
]
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(OS_MACOSX)
|
||||
#include <sched.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
@@ -724,9 +727,39 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
msg->file_descriptor_set()->CommitAll();
|
||||
#endif
|
||||
|
||||
if (bytes_written < 0 && errno != EAGAIN) {
|
||||
CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
|
||||
return false;
|
||||
if (bytes_written < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
// Not an error; the sendmsg would have blocked, so return to the
|
||||
// event loop and try again later.
|
||||
break;
|
||||
#if defined(OS_MACOSX)
|
||||
// (Note: this comment is copied from https://crrev.com/86c3d9ef4fdf6;
|
||||
// see also bug 1142693 comment #73.)
|
||||
//
|
||||
// On OS X if sendmsg() is trying to send fds between processes and
|
||||
// there isn't enough room in the output buffer to send the fd
|
||||
// structure over atomically then EMSGSIZE is returned.
|
||||
//
|
||||
// EMSGSIZE presents a problem since the system APIs can only call us
|
||||
// when there's room in the socket buffer and not when there is
|
||||
// "enough" room.
|
||||
//
|
||||
// The current behavior is to return to the event loop when EMSGSIZE
|
||||
// is received and hopefull service another FD. This is however still
|
||||
// technically a busy wait since the event loop will call us right
|
||||
// back until the receiver has read enough data to allow passing the
|
||||
// FD over atomically.
|
||||
case EMSGSIZE:
|
||||
// Because this is likely to result in a busy-wait, we'll try to make
|
||||
// it easier for the receiver to make progress.
|
||||
sched_yield();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(bytes_written) != amt_to_write) {
|
||||
|
||||
@@ -54,7 +54,11 @@
|
||||
"Goanna:MozillaRntimeMain", __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
|
||||
#endif
|
||||
# ifdef MOZ_CONTENT_SANDBOX
|
||||
# include "mozilla/Sandbox.h"
|
||||
# endif
|
||||
|
||||
#endif // MOZ_WIDGET_GONK
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
#include <binder/ProcessState.h>
|
||||
@@ -155,6 +159,16 @@ content_process_main(int argc, char* argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
// This has to happen while we're still single-threaded, and on
|
||||
// B2G that means before the Android Binder library is
|
||||
// initialized. Additional special handling is needed for Nuwa:
|
||||
// the Nuwa process itself needs to be unsandboxed, and the same
|
||||
// single-threadedness condition applies to its children; see also
|
||||
// AfterNuwaFork().
|
||||
mozilla::SandboxEarlyInit(XRE_GetProcessType(), isNuwa);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// This creates a ThreadPool for binder ipc. A ThreadPool is necessary to
|
||||
// receive binder calls, though not necessary to send binder calls.
|
||||
|
||||
+12
-5
@@ -736,7 +736,6 @@ class HashTableEntry
|
||||
void removeLive() { MOZ_ASSERT(isLive()); keyHash = sRemovedKey; mem.addr()->~T(); }
|
||||
bool isLive() const { return isLiveHash(keyHash); }
|
||||
void setCollision() { MOZ_ASSERT(isLive()); keyHash |= sCollisionBit; }
|
||||
void setCollision(HashNumber bit) { MOZ_ASSERT(isLive()); keyHash |= bit; }
|
||||
void unsetCollision() { keyHash &= ~sCollisionBit; }
|
||||
bool hasCollision() const { return keyHash & sCollisionBit; }
|
||||
bool matchHash(HashNumber hn) { return (keyHash & ~sCollisionBit) == hn; }
|
||||
@@ -1030,6 +1029,8 @@ class HashTable : private AllocPolicy
|
||||
#ifdef JS_DEBUG
|
||||
uint64_t mutationCount;
|
||||
mutable bool mEntered;
|
||||
// Note that some updates to these stats are not thread-safe. See the
|
||||
// comment on the three-argument overloading of HashTable::lookup().
|
||||
mutable struct Stats
|
||||
{
|
||||
uint32_t searches; // total number of table searches
|
||||
@@ -1227,7 +1228,12 @@ class HashTable : private AllocPolicy
|
||||
return HashPolicy::match(HashPolicy::getKey(e.get()), l);
|
||||
}
|
||||
|
||||
Entry& lookup(const Lookup& l, HashNumber keyHash, unsigned collisionBit) const
|
||||
// Warning: in order for readonlyThreadsafeLookup() to be safe this
|
||||
// function must not modify the table in any way when |collisionBit| is 0.
|
||||
// (The use of the METER() macro to increment stats violates this
|
||||
// restriction but we will live with that for now because it's enabled so
|
||||
// rarely.)
|
||||
Entry &lookup(const Lookup &l, HashNumber keyHash, unsigned collisionBit) const
|
||||
{
|
||||
MOZ_ASSERT(isLiveHash(keyHash));
|
||||
MOZ_ASSERT(!(keyHash & sCollisionBit));
|
||||
@@ -1257,12 +1263,13 @@ class HashTable : private AllocPolicy
|
||||
// Save the first removed entry pointer so we can recycle later.
|
||||
Entry* firstRemoved = nullptr;
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
if (MOZ_UNLIKELY(entry->isRemoved())) {
|
||||
if (!firstRemoved)
|
||||
firstRemoved = entry;
|
||||
} else {
|
||||
entry->setCollision(collisionBit);
|
||||
if (collisionBit == sCollisionBit)
|
||||
entry->setCollision();
|
||||
}
|
||||
|
||||
METER(stats.steps++);
|
||||
@@ -1308,7 +1315,7 @@ class HashTable : private AllocPolicy
|
||||
// Collision: double hash.
|
||||
DoubleHash dh = hash2(keyHash);
|
||||
|
||||
while(true) {
|
||||
while (true) {
|
||||
MOZ_ASSERT(!entry->isRemoved());
|
||||
entry->setCollision();
|
||||
|
||||
|
||||
+29
-16
@@ -96,6 +96,10 @@ const char js_with_str[] = "with";
|
||||
// which create a small number of atoms.
|
||||
static const uint32_t JS_STRING_HASH_COUNT = 64;
|
||||
|
||||
AtomSet::Ptr js::FrozenAtomSet::readonlyThreadsafeLookup(const AtomSet::Lookup &l) const {
|
||||
return mSet->readonlyThreadsafeLookup(l);
|
||||
}
|
||||
|
||||
struct CommonNameInfo
|
||||
{
|
||||
const char* str;
|
||||
@@ -109,6 +113,9 @@ JSRuntime::initializeAtoms(JSContext* cx)
|
||||
if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
|
||||
return false;
|
||||
|
||||
// |permanentAtoms| hasn't been created yet.
|
||||
MOZ_ASSERT(!permanentAtoms);
|
||||
|
||||
if (parentRuntime) {
|
||||
staticStrings = parentRuntime->staticStrings;
|
||||
commonNames = parentRuntime->commonNames;
|
||||
@@ -118,10 +125,6 @@ JSRuntime::initializeAtoms(JSContext* cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
permanentAtoms = cx->new_<AtomSet>();
|
||||
if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT))
|
||||
return false;
|
||||
|
||||
staticStrings = cx->new_<StaticStrings>();
|
||||
if (!staticStrings || !staticStrings->init(cx))
|
||||
return false;
|
||||
@@ -220,8 +223,8 @@ js::MarkPermanentAtoms(JSTracer* trc)
|
||||
rt->staticStrings->trace(trc);
|
||||
|
||||
if (rt->permanentAtoms) {
|
||||
for (AtomSet::Enum e(*rt->permanentAtoms); !e.empty(); e.popFront()) {
|
||||
const AtomStateEntry& entry = e.front();
|
||||
for (FrozenAtomSet::Range r(rt->permanentAtoms->all()); !r.empty(); r.popFront()) {
|
||||
const AtomStateEntry &entry = r.front();
|
||||
|
||||
JSAtom* atom = entry.asPtr();
|
||||
MarkPermanentAtom(trc, atom, "permanent_table");
|
||||
@@ -263,21 +266,22 @@ JSRuntime::sweepAtoms()
|
||||
}
|
||||
|
||||
bool
|
||||
JSRuntime::transformToPermanentAtoms()
|
||||
JSRuntime::transformToPermanentAtoms(JSContext *cx)
|
||||
{
|
||||
MOZ_ASSERT(!parentRuntime);
|
||||
|
||||
// All static strings were created as permanent atoms, now move the contents
|
||||
// of the atoms table into permanentAtoms and mark each as permanent.
|
||||
|
||||
MOZ_ASSERT(permanentAtoms && permanentAtoms->empty());
|
||||
MOZ_ASSERT(!permanentAtoms);
|
||||
permanentAtoms = cx->new_<FrozenAtomSet>(atoms_); // takes ownership of atoms_
|
||||
|
||||
AtomSet* temp = atoms_;
|
||||
atoms_ = permanentAtoms;
|
||||
permanentAtoms = temp;
|
||||
atoms_ = cx->new_<AtomSet>();
|
||||
if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
|
||||
return false;
|
||||
|
||||
for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) {
|
||||
AtomStateEntry entry = e.front();
|
||||
for (FrozenAtomSet::Range r(permanentAtoms->all()); !r.empty(); r.popFront()) {
|
||||
AtomStateEntry entry = r.front();
|
||||
JSAtom* atom = entry.asPtr();
|
||||
atom->morphIntoPermanentAtom();
|
||||
}
|
||||
@@ -295,6 +299,7 @@ AtomIsInterned(JSContext* cx, JSAtom* atom)
|
||||
AtomHasher::Lookup lookup(atom);
|
||||
|
||||
/* Likewise, permanent strings are considered to be interned. */
|
||||
MOZ_ASSERT(cx->isPermanentAtomsInitialized());
|
||||
AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
|
||||
if (p)
|
||||
return true;
|
||||
@@ -319,9 +324,16 @@ AtomizeAndCopyChars(ExclusiveContext* cx, const CharT* tbchars, size_t length, I
|
||||
|
||||
AtomHasher::Lookup lookup(tbchars, length);
|
||||
|
||||
AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
|
||||
if (pp)
|
||||
return pp->asPtr();
|
||||
// Note: when this function is called while the permanent atoms table is
|
||||
// being initialized (in initializeAtoms()), |permanentAtoms| is not yet
|
||||
// initialized so this lookup is always skipped. Only once
|
||||
// transformToPermanentAtoms() is called does |permanentAtoms| get
|
||||
// initialized and then this lookup will go ahead.
|
||||
if (cx->isPermanentAtomsInitialized()) {
|
||||
AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
|
||||
if (pp)
|
||||
return pp->asPtr();
|
||||
}
|
||||
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
|
||||
@@ -376,6 +388,7 @@ js::AtomizeString(ExclusiveContext* cx, JSString* str,
|
||||
AtomHasher::Lookup lookup(&atom);
|
||||
|
||||
/* Likewise, permanent atoms are always interned. */
|
||||
MOZ_ASSERT(cx->isPermanentAtomsInitialized());
|
||||
AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
|
||||
if (p)
|
||||
return &atom;
|
||||
|
||||
@@ -117,6 +117,30 @@ struct AtomHasher
|
||||
|
||||
typedef HashSet<AtomStateEntry, AtomHasher, SystemAllocPolicy> AtomSet;
|
||||
|
||||
// This class is a wrapper for AtomSet that is used to ensure the AtomSet is
|
||||
// not modified. It should only expose read-only methods from AtomSet.
|
||||
// Note however that the atoms within the table can be marked during GC.
|
||||
class FrozenAtomSet
|
||||
{
|
||||
AtomSet *mSet;
|
||||
|
||||
public:
|
||||
// This constructor takes ownership of the passed-in AtomSet.
|
||||
explicit FrozenAtomSet(AtomSet *set) { mSet = set; }
|
||||
|
||||
~FrozenAtomSet() { js_delete(mSet); }
|
||||
|
||||
AtomSet::Ptr readonlyThreadsafeLookup(const AtomSet::Lookup &l) const;
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
return mSet->sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
typedef AtomSet::Range Range;
|
||||
|
||||
AtomSet::Range all() const { return mSet->all(); }
|
||||
};
|
||||
|
||||
class PropertyName;
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ js::NewContext(JSRuntime* rt, size_t stackChunkSize)
|
||||
ok = rt->initSelfHosting(cx);
|
||||
|
||||
if (ok && !rt->parentRuntime)
|
||||
ok = rt->transformToPermanentAtoms();
|
||||
ok = rt->transformToPermanentAtoms(cx);
|
||||
|
||||
JS_EndRequest(cx);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user