Merge m-c to fx-team a=merge

This commit is contained in:
Wes Kocher 2015-04-22 17:27:15 -07:00
commit 53b2bacf3e
1128 changed files with 83355 additions and 7879 deletions

View File

@ -17,8 +17,6 @@ class AccessibleWrap;
} // namespace a11y
} // namespace mozilla
struct MaiUtilClass;
extern "C" {
void actionInterfaceInitCB(AtkActionIface* aIface);
void componentInterfaceInitCB(AtkComponentIface* aIface);

View File

@ -23,7 +23,6 @@ struct nsRect;
class nsIFrame;
class nsIAtom;
class nsIPersistentProperties;
class nsView;
namespace mozilla {
namespace a11y {
@ -39,7 +38,6 @@ class HTMLLIAccessible;
class HyperTextAccessible;
class ImageAccessible;
class KeyBinding;
class MathMLAccessible;
class ProxyAccessible;
class Relation;
class RootAccessible;

View File

@ -23,8 +23,6 @@
class nsAccessiblePivot;
class nsIScrollableView;
const uint32_t kDefaultCacheLength = 128;
namespace mozilla {

View File

@ -8,8 +8,6 @@
#include "BaseAccessibles.h"
class nsGenericHTMLElement;
namespace mozilla {
namespace a11y {

View File

@ -8,8 +8,6 @@
#include "HTMLFormControlAccessible.h"
class nsIMutableArray;
namespace mozilla {
namespace a11y {

View File

@ -10,7 +10,6 @@
#include "TableAccessible.h"
#include "TableCellAccessible.h"
class nsITableLayout;
class nsITableCellLayout;
namespace mozilla {

View File

@ -20,11 +20,7 @@ class Accessible;
} // namespace a11y
} // namespace mozilla
class nsINode;
class nsIContent;
class nsIFrame;
class nsIPresShell;
class nsPluginFrame;
// 0e7e6879-854b-4260-bc6e-525b5fb5cf34
#define NS_IACCESSIBILITYSERVICE_IID \

View File

@ -191,6 +191,12 @@ this.EventManager.prototype = {
let acc = aEvent.accessible;
if (acc === this.contentControl.vc.position) {
this.present(Presentation.nameChanged(acc));
} else {
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
['text', 'all']);
if (liveRegion) {
this.present(Presentation.nameChanged(acc, isPolite));
}
}
break;
}
@ -293,6 +299,12 @@ this.EventManager.prototype = {
if (position === target ||
Utils.getEmbeddedControl(position) === target) {
this.present(Presentation.valueChanged(target));
} else {
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
['text', 'all']);
if (liveRegion) {
this.present(Presentation.valueChanged(target, isPolite));
}
}
}
}

View File

@ -523,18 +523,19 @@ B2GPresenter.prototype.pivotChanged =
};
B2GPresenter.prototype.nameChanged =
function B2GPresenter_nameChanged(aAccessible) {
function B2GPresenter_nameChanged(aAccessible, aIsPolite = true) {
return {
type: this.type,
details: {
eventType: 'name-change',
data: aAccessible.name
data: aAccessible.name,
options: {enqueue: aIsPolite}
}
};
};
B2GPresenter.prototype.valueChanged =
function B2GPresenter_valueChanged(aAccessible) {
function B2GPresenter_valueChanged(aAccessible, aIsPolite = true) {
// the editable value changes are handled in the text changed presenter
if (Utils.getState(aAccessible).contains(States.EDITABLE)) {
@ -545,7 +546,8 @@ B2GPresenter.prototype.valueChanged =
type: this.type,
details: {
eventType: 'value-change',
data: aAccessible.value
data: aAccessible.value,
options: {enqueue: aIsPolite}
}
};
};

View File

@ -15,8 +15,6 @@
namespace mozilla {
namespace a11y {
struct objc_class;
class RootAccessibleWrap : public RootAccessible
{
public:

View File

@ -44,6 +44,17 @@
document.getElementById('fruit').setAttribute('aria-label', 'banana');
}
function renameSlider() {
document.getElementById('slider').setAttribute(
'aria-label', 'mover');
}
function changeSliderValue() {
document.getElementById('slider').setAttribute('aria-valuenow', '5');
document.getElementById('slider').setAttribute(
'aria-valuetext', 'medium');
}
</script>
<style>
#windows {
@ -89,5 +100,9 @@
</div>
<button id="home">Home</button>
<button id="fruit" aria-label="apple"></button>
<div id="live" aria-live="polite" aria-label="live">
<div id="slider" role="slider" aria-label="slider" aria-valuemin="0"
aria-valuemax="10" aria-valuenow="0"></div>
</div>
</body>
</html>

View File

@ -629,7 +629,7 @@ ExpectedNameChange.prototype = Object.create(ExpectedPresent.prototype);
function ExpectedValueChange(aValue, aOptions) {
ExpectedPresent.call(this, {
eventType: 'value-change',
data: [aValue]
data: aValue
}, null, aOptions);
}

View File

@ -58,8 +58,12 @@
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])],
[ContentMessages.simpleMoveNext,
new ExpectedCursorChange(['slider', '0', {'string': 'slider'}])],
// Simple traversal backward
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])],
[ContentMessages.simpleMovePrevious,
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
[ContentMessages.simpleMovePrevious,
@ -92,7 +96,7 @@
// Move from an inner frame to the last element in the parent doc
[ContentMessages.simpleMoveLast,
new ExpectedCursorChange(
['apple', {'string': 'pushbutton'}], { b2g_todo: true })],
['slider', '0', {'string': 'slider'}], { b2g_todo: true })],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
@ -147,6 +151,12 @@
new ExpectedCursorChange(['apple', {'string': 'pushbutton'}])],
[doc.defaultView.renameFruit, new ExpectedNameChange('banana')],
// Name and value changes inside a live-region (no cursor present)
[doc.defaultView.renameSlider,
new ExpectedNameChange('mover')],
[doc.defaultView.changeSliderValue,
new ExpectedValueChange('medium')],
// Blur button and reset cursor
[ContentMessages.focusSelector('button#fruit', true), null],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
@ -222,14 +232,14 @@
// Open dialog in outer doc, while cursor is also in outer doc
[ContentMessages.simpleMoveLast,
new ExpectedCursorChange(['banana', {'string': 'pushbutton'}])],
new ExpectedCursorChange(['mover'])],
[doc.defaultView.showAlert,
new ExpectedCursorChange(['This is an alert!',
{'string': 'headingLevel', 'args': [1]},
{'string': 'dialog'}])],
[doc.defaultView.hideAlert,
new ExpectedCursorChange(['banana', {'string': 'pushbutton'}])],
new ExpectedCursorChange(['mover'])],
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],

View File

@ -14,7 +14,6 @@
#include "nsCOMPtr.h"
#include "nsRefPtrHashtable.h"
class nsIArray;
class nsIContent;
namespace mozilla {

View File

@ -14,8 +14,6 @@
#include "XULMenuAccessible.h"
#include "XULSelectControlAccessible.h"
class nsIWeakReference;
namespace mozilla {
namespace a11y {

View File

@ -323,7 +323,7 @@ pref("media.fragmented-mp4.gonk.enabled", true);
pref("media.video-queue.default-size", 3);
// optimize images' memory usage
pref("image.decode-only-on-draw.enabled", true);
pref("image.decode-only-on-draw.enabled", false);
pref("image.mem.allow_locking_in_content_processes", true);
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
// Almost everything that was factored into 'max_decoded_image_kb' is now stored
@ -1124,8 +1124,5 @@ pref("dom.mozSettings.allowForceReadOnly", false);
// RequestSync API is enabled by default on B2G.
pref("dom.requestSync.enabled", true);
// Use vsync aligned rendering
pref("gfx.vsync.hw-vsync.enabled", true);
pref("gfx.vsync.compositor", true);
// Resample touch events on b2g
pref("gfx.touch.resample", true);
pref("gfx.vsync.refreshdriver", true);

View File

@ -30,14 +30,19 @@ html xul|scrollbar {
pointer-events: none;
}
/* Scrollbar code will reset the margin to the correct side depending on
layout.scrollbar.side pref */
xul|scrollbar[orient="vertical"] {
margin-left: -8px;
-moz-margin-start: -8px;
min-width: 8px;
max-width: 8px;
}
/* workaround for bug 1119057: as -moz-margin-start may not work as expected,
* force a right margin value in RTL mode. */
[dir="rtl"] xul|scrollbar[root="true"][orient="vertical"] {
-moz-margin-start: unset;
margin-right: -8px;
}
xul|scrollbar[orient="vertical"] xul|thumb {
max-width: 6px !important;
min-width: 6px !important;

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "a7dcc5fb595030dab140d5ff0e7eb5ef04017d51",
"git_revision": "9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "5e00921aa36301b179b4912d352e6bcc0de89edc",
"revision": "6238380e300e25c4ec8aea2a8804d0ca3675f7fb",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="90f848a40efad820ab00fa52bec52dff37255b12"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="a7dcc5fb595030dab140d5ff0e7eb5ef04017d51"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9d4f756aa35cb7f030a92f3c1f65fb55254ddd1d"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -209,6 +209,7 @@
@RESPATH@/components/dom_json.xpt
@RESPATH@/components/dom_messages.xpt
@RESPATH@/components/dom_power.xpt
@RESPATH@/components/dom_push.xpt
@RESPATH@/components/dom_quota.xpt
@RESPATH@/components/dom_range.xpt
@RESPATH@/components/dom_security.xpt
@ -631,7 +632,7 @@
@RESPATH@/components/AppsService.manifest
@RESPATH@/components/Push.js
@RESPATH@/components/Push.manifest
@RESPATH@/components/PushServiceLauncher.js
@RESPATH@/components/PushNotificationService.js
@RESPATH@/components/InterAppComm.manifest
@RESPATH@/components/InterAppCommService.js

View File

@ -30,6 +30,7 @@ externalProtocolUnknown=<Unknown>
externalProtocolChkMsg=Remember my choice for all links of this type.
externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences.
phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.

View File

@ -374,6 +374,7 @@
<h1 id="et_nssFailure2">&nssFailure2.title;</h1>
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
<h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
<h1 id="et_unwantedBlocked">&unwantedBlocked.title;</h1>
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
@ -401,6 +402,7 @@
<div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
<div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
<div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div>
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>

View File

@ -79,6 +79,9 @@
case "phishingBlocked" :
initPage_phishing();
break;
case "unwantedBlocked" :
initPage_unwanted();
break;
}
}
@ -87,7 +90,7 @@
*/
function initPage_malware()
{
// Remove phishing strings
// Remove phishing and unwanted strings
var el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
@ -97,18 +100,57 @@
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorTitleText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_unwanted");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("malware_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_malware")
.innerHTML;
}
/**
* Initialize custom strings and functionality for blocked malware case
*/
function initPage_unwanted()
{
// Remove phishing and malware strings
var el = document.getElementById("errorTitleText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_phishing");
el.parentNode.removeChild(el);
el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("unwanted_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_unwanted")
.innerHTML;
}
/**
* Initialize custom strings and functionality for blocked phishing case
*/
function initPage_phishing()
{
// Remove malware strings
// Remove malware and unwanted strings
var el = document.getElementById("errorTitleText_malware");
el.parentNode.removeChild(el);
@ -118,6 +160,15 @@
el = document.getElementById("errorLongDescText_malware");
el.parentNode.removeChild(el);
el = document.getElementById("errorTitleText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_unwanted");
el.parentNode.removeChild(el);
el = document.getElementById("errorLongDescText_unwanted");
el.parentNode.removeChild(el);
// Set sitename
document.getElementById("phishing_sitename").textContent = getHostString();
document.title = document.getElementById("errorTitleText_phishing")
@ -161,6 +212,7 @@
<div id="errorTitle">
<h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title;</h1>
<h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1>
<h1 id="errorTitleText_unwanted">&safeb.blocked.unwantedPage.title;</h1>
</div>
<div id="errorLongContent">
@ -169,12 +221,14 @@
<div id="errorShortDesc">
<p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc;</p>
<p id="errorShortDescText_malware">&safeb.blocked.malwarePage.shortDesc;</p>
<p id="errorShortDescText_unwanted">&safeb.blocked.unwantedPage.shortDesc;</p>
</div>
<!-- Long Description -->
<div id="errorLongDesc">
<p id="errorLongDescText_phishing">&safeb.blocked.phishingPage.longDesc;</p>
<p id="errorLongDescText_malware">&safeb.blocked.malwarePage.longDesc;</p>
<p id="errorLongDescText_unwanted">&safeb.blocked.unwantedPage.longDesc;</p>
</div>
<!-- Action buttons -->

View File

@ -2659,7 +2659,7 @@ let BrowserOnClick = {
msg.data.sslStatusAsString);
break;
case "Browser:SiteBlockedError":
this.onAboutBlocked(msg.data.elementId, msg.data.isMalware,
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
msg.data.isTopFrame, msg.data.location);
break;
case "Browser:EnableOnlineMode":
@ -2843,10 +2843,15 @@ let BrowserOnClick = {
}
},
onAboutBlocked: function (elementId, isMalware, isTopFrame, location) {
// Depending on what page we are displaying here (malware/phishing)
onAboutBlocked: function (elementId, reason, isTopFrame, location) {
// Depending on what page we are displaying here (malware/phishing/unwanted)
// use the right strings and links for each.
let bucketName = isMalware ? "WARNING_MALWARE_PAGE_":"WARNING_PHISHING_PAGE_";
let bucketName = "WARNING_PHISHING_PAGE_";
if (reason === 'malware') {
bucketName = "WARNING_MALWARE_PAGE_";
} else if (reason === 'unwanted') {
bucketName = "WARNING_UNWANTED_PAGE_";
}
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
let nsISecTel = Ci.nsISecurityUITelemetry;
bucketName += isTopFrame ? "TOP_" : "FRAME_";
@ -2857,33 +2862,19 @@ let BrowserOnClick = {
break;
case "reportButton":
// This is the "Why is this site blocked" button. For malware,
// we can fetch a site-specific report, for phishing, we redirect
// to the generic page describing phishing protection.
// This is the "Why is this site blocked" button. We redirect
// to the generic page describing phishing/malware protection.
// We log even if malware/phishing info URL couldn't be found:
// We log even if malware/phishing/unwanted info URL couldn't be found:
// the measurement is for how many users clicked the WHY BLOCKED button
secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
if (isMalware) {
// Get the stop badware "why is this blocked" report url,
// append the current url, and go there.
try {
let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
reportURL += location;
gBrowser.loadURI(reportURL);
} catch (e) {
Components.utils.reportError("Couldn't get malware report URL: " + e);
}
}
else { // It's a phishing site, not malware
openHelpLink("phishing-malware", false, "current");
}
openHelpLink("phishing-malware", false, "current");
break;
case "ignoreWarningButton":
secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
this.ignoreWarningButton(isMalware);
this.ignoreWarningButton(reason);
break;
}
},
@ -2910,7 +2901,7 @@ let BrowserOnClick = {
}
},
ignoreWarningButton: function (isMalware) {
ignoreWarningButton: function (reason) {
// Allow users to override and continue through to the site,
// but add a notify bar as a reminder, so that they don't lose
// track after, e.g., tab switching.
@ -2929,7 +2920,7 @@ let BrowserOnClick = {
}];
let title;
if (isMalware) {
if (reason === 'malware') {
title = gNavigatorBundle.getString("safebrowsing.reportedAttackSite");
buttons[1] = {
label: gNavigatorBundle.getString("safebrowsing.notAnAttackButton.label"),
@ -2938,7 +2929,7 @@ let BrowserOnClick = {
openUILinkIn(gSafeBrowsing.getReportURL('MalwareError'), 'tab');
}
};
} else {
} else if (reason === 'phishing') {
title = gNavigatorBundle.getString("safebrowsing.reportedWebForgery");
buttons[1] = {
label: gNavigatorBundle.getString("safebrowsing.notAForgeryButton.label"),
@ -2947,6 +2938,10 @@ let BrowserOnClick = {
openUILinkIn(gSafeBrowsing.getReportURL('Error'), 'tab');
}
};
} else if (reason === 'unwanted') {
title = gNavigatorBundle.getString("safebrowsing.reportedUnwantedSite");
// There is no button for reporting errors since Google doesn't currently
// provide a URL endpoint for these reports.
}
let notificationBox = gBrowser.getNotificationBox();
@ -3994,6 +3989,11 @@ var XULBrowserWindow = {
},
showTooltip: function (x, y, tooltip) {
if (Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService).
getCurrentSession()) {
return;
}
// The x,y coordinates are relative to the <browser> element using
// the chrome zoom level.
let elt = document.getElementById("remoteBrowserTooltip");

View File

@ -123,6 +123,13 @@ let handleContentContextMenu = function (event) {
InlineSpellCheckerContent.initContextMenu(event, editFlags, this);
}
// Set the event target first as the copy image command needs it to
// determine what was context-clicked on. Then, update the state of the
// commands on the context menu.
docShell.contentViewer.QueryInterface(Ci.nsIContentViewerEdit)
.setCommandNode(event.target);
event.target.ownerDocument.defaultView.updateCommands("contentcontextmenu");
let customMenuItems = PageMenuChild.build(event.target);
let principal = doc.nodePrincipal;
sendSyncMessage("contextmenu",
@ -377,9 +384,15 @@ let ClickEventHandler = {
},
onAboutBlocked: function (targetElement, ownerDoc) {
var reason = 'phishing';
if (/e=malwareBlocked/.test(ownerDoc.documentURI)) {
reason = 'malware';
} else if (/e=unwantedBlocked/.test(ownerDoc.documentURI)) {
reason = 'unwanted';
}
sendAsyncMessage("Browser:SiteBlockedError", {
location: ownerDoc.location.href,
isMalware: /e=malwareBlocked/.test(ownerDoc.documentURI),
reason: reason,
elementId: targetElement.getAttribute("id"),
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView)
});

View File

@ -628,7 +628,9 @@ nsContextMenu.prototype = {
this.inSyntheticDoc = ownerDoc.mozSyntheticDocument;
// First, do checks for nodes that never have children.
if (this.target.nodeType == Node.ELEMENT_NODE) {
// See if the user clicked on an image.
// See if the user clicked on an image. This check mirrors
// nsDocumentViewer::GetInImage. Make sure to update both if this is
// changed.
if (this.target instanceof Ci.nsIImageLoadingContent &&
this.target.currentURI) {
this.onImage = true;

View File

@ -486,6 +486,11 @@ Sanitizer.prototype = {
.getService(Ci.nsISiteSecurityService);
sss.clearAll();
// Clear all push notification subscriptions
var push = Cc["@mozilla.org/push/NotificationService;1"]
.getService(Ci.nsIPushNotificationService);
push.clearAll();
TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS");
},

View File

@ -144,7 +144,6 @@ skip-if = e10s # bug 967873 means permitUnload doesn't work in e10s mode
[browser_bookmark_titles.js]
skip-if = buildapp == 'mulet' || toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)
[browser_bug304198.js]
skip-if = e10s
[browser_bug321000.js]
skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
[browser_bug329212.js]
@ -215,7 +214,6 @@ skip-if = e10s # Bug 1093373 - relies on browser.sessionHistory
[browser_bug562649.js]
[browser_bug563588.js]
[browser_bug565575.js]
skip-if = e10s
[browser_bug565667.js]
skip-if = toolkit != "cocoa"
[browser_bug567306.js]
@ -250,7 +248,6 @@ skip-if = e10s && debug
[browser_bug647886.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1093373 - Relies on browser.sessionHistory
[browser_bug655584.js]
skip-if = e10s
[browser_bug664672.js]
[browser_bug676619.js]
skip-if = buildapp == 'mulet' || os == "mac" # mac: Intermittent failures, bug 925225
@ -337,7 +334,6 @@ skip-if = os == "linux" # Linux: Intermittent failures, bug 917535
[browser_menuButtonFitts.js]
skip-if = os != "win" # The Fitts Law menu button is only supported on Windows (bug 969376)
[browser_middleMouse_noJSPaste.js]
skip-if = e10s # Bug 921952 - Content:Click event issues
[browser_minimize.js]
skip-if = e10s # Bug 1100664 - test directly access content docShells (TypeError: gBrowser.docShell is null)
[browser_mixedcontent_securityflags.js]
@ -388,7 +384,7 @@ skip-if = buildapp == 'mulet' || e10s # e10s: Bug 933103 - mochitest's EventUtil
[browser_save_link_when_window_navigates.js]
skip-if = buildapp == 'mulet' || e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
[browser_save_video.js]
skip-if = buildapp == 'mulet' || e10s # Bug 1100698 - test uses synthesizeMouse and then does a load of other stuff that breaks in e10s
skip-if = buildapp == 'mulet'
[browser_save_video_frame.js]
[browser_scope.js]
[browser_searchSuggestionUI.js]
@ -465,7 +461,6 @@ skip-if = (os == "win" && !debug) || e10s # Bug 1007418
[browser_windowopen_reflows.js]
skip-if = buildapp == 'mulet'
[browser_wyciwyg_urlbarCopying.js]
skip-if = e10s # Bug 1100703 - test directly manipulates content (content.document.getElementById)
[browser_zbug569342.js]
skip-if = e10s # Bug 1094240 - has findbar-related failures
[browser_registerProtocolHandler_notification.js]

View File

@ -2,9 +2,7 @@
* 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/. */
function test() {
waitForExplicitFinish();
add_task(function* () {
let charsToDelete, deletedURLTab, fullURLTab, partialURLTab, testPartialURL, testURL;
charsToDelete = 5;
@ -13,112 +11,96 @@ function test() {
partialURLTab = gBrowser.addTab();
testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
let loaded1 = BrowserTestUtils.browserLoaded(deletedURLTab.linkedBrowser, testURL);
let loaded2 = BrowserTestUtils.browserLoaded(fullURLTab.linkedBrowser, testURL);
let loaded3 = BrowserTestUtils.browserLoaded(partialURLTab.linkedBrowser, testURL);
deletedURLTab.linkedBrowser.loadURI(testURL);
fullURLTab.linkedBrowser.loadURI(testURL);
partialURLTab.linkedBrowser.loadURI(testURL);
yield Promise.all([loaded1, loaded2, loaded3]);
testURL = gURLBar.trimValue(testURL);
testPartialURL = testURL.substr(0, (testURL.length - charsToDelete));
function cleanUp() {
gBrowser.removeTab(fullURLTab);
gBrowser.removeTab(partialURLTab);
gBrowser.removeTab(deletedURLTab);
}
function cycleTabs() {
gBrowser.selectedTab = fullURLTab;
function* cycleTabs() {
yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
gBrowser.selectedTab = partialURLTab;
yield BrowserTestUtils.switchTab(gBrowser, partialURLTab);
is(gURLBar.textValue, testPartialURL, 'gURLBar.textValue should be testPartialURL after switching back to partialURLTab');
gBrowser.selectedTab = deletedURLTab;
yield BrowserTestUtils.switchTab(gBrowser, deletedURLTab);
is(gURLBar.textValue, '', 'gURLBar.textValue should be "" after switching back to deletedURLTab');
gBrowser.selectedTab = fullURLTab;
yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after switching back to fullURLTab');
}
// function borrowed from browser_bug386835.js
function load(tab, url, cb) {
tab.linkedBrowser.addEventListener("load", function (event) {
event.currentTarget.removeEventListener("load", arguments.callee, true);
cb();
}, true);
tab.linkedBrowser.loadURI(url);
}
function urlbarBackspace(cb) {
gBrowser.selectedBrowser.focus();
gURLBar.addEventListener("focus", function () {
gURLBar.removeEventListener("focus", arguments.callee, false);
function urlbarBackspace() {
return new Promise((resolve, reject) => {
gBrowser.selectedBrowser.focus();
gURLBar.addEventListener("input", function () {
gURLBar.removeEventListener("input", arguments.callee, false);
cb();
resolve();
}, false);
executeSoon(function () {
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
});
}, false);
gURLBar.focus();
gURLBar.focus();
EventUtils.synthesizeKey("VK_BACK_SPACE", {});
});
}
function prepareDeletedURLTab(cb) {
gBrowser.selectedTab = deletedURLTab;
function* prepareDeletedURLTab() {
yield BrowserTestUtils.switchTab(gBrowser, deletedURLTab);
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to deletedURLTab');
// simulate the user removing the whole url from the location bar
gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", true);
urlbarBackspace(function () {
is(gURLBar.textValue, "", 'gURLBar.textValue should be "" (just set)');
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll"))
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
cb();
});
yield urlbarBackspace();
is(gURLBar.textValue, "", 'gURLBar.textValue should be "" (just set)');
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll")) {
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
}
}
function prepareFullURLTab(cb) {
gBrowser.selectedTab = fullURLTab;
function* prepareFullURLTab() {
yield BrowserTestUtils.switchTab(gBrowser, fullURLTab);
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to fullURLTab');
cb();
}
function preparePartialURLTab(cb) {
gBrowser.selectedTab = partialURLTab;
function* preparePartialURLTab() {
yield BrowserTestUtils.switchTab(gBrowser, partialURLTab);
is(gURLBar.textValue, testURL, 'gURLBar.textValue should be testURL after initial switch to partialURLTab');
// simulate the user removing part of the url from the location bar
gPrefService.setBoolPref("browser.urlbar.clickSelectsAll", false);
var deleted = 0;
urlbarBackspace(function () {
let deleted = 0;
while (deleted < charsToDelete) {
yield urlbarBackspace(arguments.callee);
deleted++;
if (deleted < charsToDelete) {
urlbarBackspace(arguments.callee);
} else {
is(gURLBar.textValue, testPartialURL, "gURLBar.textValue should be testPartialURL (just set)");
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll"))
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
cb();
}
});
}
is(gURLBar.textValue, testPartialURL, "gURLBar.textValue should be testPartialURL (just set)");
if (gPrefService.prefHasUserValue("browser.urlbar.clickSelectsAll")) {
gPrefService.clearUserPref("browser.urlbar.clickSelectsAll");
}
}
function runTests() {
testURL = gURLBar.trimValue(testURL);
testPartialURL = testURL.substr(0, (testURL.length - charsToDelete));
// prepare the three tabs required by this test
// prepare the three tabs required by this test
prepareFullURLTab(function () {
preparePartialURLTab(function () {
prepareDeletedURLTab(function () {
// now cycle the tabs and make sure everything looks good
cycleTabs();
cleanUp();
finish();
});
});
});
}
// First tab
yield* prepareFullURLTab();
yield* preparePartialURLTab();
yield* prepareDeletedURLTab();
// now cycle the tabs and make sure everything looks good
yield* cycleTabs();
cleanUp();
});
load(deletedURLTab, testURL, function() {
load(fullURLTab, testURL, function() {
load(partialURLTab, testURL, runTests);
});
});
}

View File

@ -1,13 +1,14 @@
function test() {
add_task(function* () {
gBrowser.selectedBrowser.focus();
BrowserOpenTab();
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => BrowserOpenTab(), false);
ok(gURLBar.focused, "location bar is focused for a new tab");
gBrowser.selectedTab = gBrowser.tabs[0];
yield BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[0]);
ok(!gURLBar.focused, "location bar isn't focused for the previously selected tab");
gBrowser.selectedTab = gBrowser.tabs[1];
yield BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[1]);
ok(gURLBar.focused, "location bar is re-focused when selecting the new tab");
gBrowser.removeCurrentTab();
}
});

View File

@ -4,20 +4,20 @@
// Bug 655584 - awesomebar suggestions don't update after tab is closed
function test() {
add_task(function* () {
var tab1 = gBrowser.addTab();
var tab2 = gBrowser.addTab();
// When urlbar in a new tab is focused, and a tab switch occurs,
// the urlbar popup should be closed
gBrowser.selectedTab = tab2;
yield BrowserTestUtils.switchTab(gBrowser, tab2);
gURLBar.focus(); // focus the urlbar in the tab we will switch to
gBrowser.selectedTab = tab1;
yield BrowserTestUtils.switchTab(gBrowser, tab1);
gURLBar.openPopup();
gBrowser.selectedTab = tab2;
yield BrowserTestUtils.switchTab(gBrowser, tab2);
ok(!gURLBar.popupOpen, "urlbar focused in tab to switch to, close popup");
// cleanup
gBrowser.removeCurrentTab();
gBrowser.removeCurrentTab();
}
});

View File

@ -1,7 +1,9 @@
// This test is used to check copy and paste in editable areas to ensure that non-text
// types (html and images) are copied to and pasted from the clipboard properly.
let testPage = "<div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>";
let testPage = "<body style='margin: 0'><img id='img' tabindex='1' src='http://example.org/browser/browser/base/content/test/general/moz.png'>" +
" <div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>" +
"</body>";
add_task(function*() {
let tab = gBrowser.addTab();
@ -12,7 +14,12 @@ add_task(function*() {
yield promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
let results = yield ContentTask.spawn(browser, {}, function* () {
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
let results = yield ContentTask.spawn(browser, { modifier: modifier },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
main.focus();
@ -20,10 +27,7 @@ add_task(function*() {
const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
const modifier = (content.navigator.platform.indexOf("Mac") >= 0) ?
Components.interfaces.nsIDOMWindowUtils.MODIFIER_META :
Components.interfaces.nsIDOMWindowUtils.MODIFIER_CONTROL;
const modifier = arg.modifier;
function sendKey(key)
{
if (utils.sendKeyEvent("keydown", key, 0, modifier)) {
@ -46,7 +50,7 @@ add_task(function*() {
selection.modify("extend", "right", "word");
selection.modify("extend", "right", "word");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("copy", function copyEvent(event) {
removeEventListener("copy", copyEvent, true);
// The data is empty as the selection is copied during the event default phase.
@ -59,7 +63,7 @@ add_task(function*() {
selection.modify("move", "right", "line");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
@ -80,7 +84,7 @@ add_task(function*() {
selection.modify("extend", "left", "word");
selection.modify("extend", "left", "character");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("cut", function copyEvent(event) {
removeEventListener("cut", copyEvent, true);
event.clipboardData.setData("text/plain", "Some text");
@ -94,7 +98,7 @@ add_task(function*() {
selection.modify("move", "left", "line");
yield new content.Promise((resolve, reject) => {
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
@ -110,6 +114,7 @@ add_task(function*() {
});
is(main.innerHTML, "<i>Italic</i> Test <b>Bold</b> After<b></b>", "Copy and paste html 2");
return results;
});
@ -118,6 +123,61 @@ add_task(function*() {
ok(results[t].startsWith("PASSED"), results[t]);
}
// Next, check that the Copy Image command works.
// The context menu needs to be opened to properly initialize for the copy
// image command to run.
let contextMenu = document.getElementById("contentAreaContextMenu");
let contextMenuShown = promisePopupShown(contextMenu);
BrowserTestUtils.synthesizeMouseAtCenter("#img", { type: "contextmenu", button: 2 }, gBrowser.selectedBrowser);
yield contextMenuShown;
document.getElementById("context-copyimage-contents").doCommand();
contextMenu.hidePopup();
yield promisePopupHidden(contextMenu);
// Focus the content again
yield SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
let expectedContent = yield ContentTask.spawn(browser, { modifier: modifier },
function* (arg) {
var doc = content.document;
var main = doc.getElementById("main");
main.focus();
yield new Promise((resolve, reject) => {
addEventListener("paste", function copyEvent(event) {
removeEventListener("paste", copyEvent, true);
let clipboardData = event.clipboardData;
// DataTransfer doesn't support the image types yet, so only text/html
// will be present.
if (clipboardData.getData("text/html") !=
'<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">') {
reject();
}
resolve();
}, true)
const utils = content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
const modifier = arg.modifier;
if (utils.sendKeyEvent("keydown", "v", 0, modifier)) {
utils.sendKeyEvent("keypress", "v", "v".charCodeAt(0), modifier);
}
utils.sendKeyEvent("keyup", "v", 0, modifier);
});
// Return the new content which should now include an image.
return main.innerHTML;
});
is(expectedContent, '<i>Italic</i> <img id="img" tabindex="1" ' +
'src="http://example.org/browser/browser/base/content/test/general/moz.png">' +
'Test <b>Bold</b> After<b></b>', "Paste after copy image");
gBrowser.removeCurrentTab();
});

View File

@ -3,51 +3,32 @@
const middleMousePastePref = "middlemouse.contentLoadURL";
const autoScrollPref = "general.autoScroll";
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref(middleMousePastePref, true);
Services.prefs.setBoolPref(autoScrollPref, false);
let tab = gBrowser.selectedTab = gBrowser.addTab();
add_task(function* () {
yield pushPrefs([middleMousePastePref, true], [autoScrollPref, false]);
registerCleanupFunction(function () {
Services.prefs.clearUserPref(middleMousePastePref);
Services.prefs.clearUserPref(autoScrollPref);
gBrowser.removeTab(tab);
});
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
addPageShowListener(function () {
let pagePrincipal = gBrowser.contentPrincipal;
// copy javascript URI to the clipboard
let url = "javascript:http://www.example.com/";
waitForClipboard(url,
function() {
Components.classes["@mozilla.org/widget/clipboardhelper;1"]
.getService(Components.interfaces.nsIClipboardHelper)
.copyString(url, document);
},
function () {
// Middle click on the content area
info("Middle clicking");
EventUtils.sendMouseEvent({type: "click", button: 1}, gBrowser);
},
function() {
ok(false, "Failed to copy URL to the clipboard");
finish();
}
);
addPageShowListener(function () {
is(gBrowser.currentURI.spec, url.replace(/^javascript:/, ""), "url loaded by middle click doesn't include JS");
finish();
let url = "javascript:http://www.example.com/";
yield new Promise((resolve, reject) => {
SimpleTest.waitForClipboard(url, () => {
Components.classes["@mozilla.org/widget/clipboardhelper;1"]
.getService(Components.interfaces.nsIClipboardHelper)
.copyString(url, document);
}, resolve, () => {
ok(false, "Clipboard copy failed");
reject();
});
});
}
function addPageShowListener(func) {
gBrowser.selectedBrowser.addEventListener("pageshow", function loadListener() {
gBrowser.selectedBrowser.removeEventListener("pageshow", loadListener, false);
func();
});
}
let middlePagePromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
// Middle click on the content area
info("Middle clicking");
yield BrowserTestUtils.synthesizeMouse(null, 10, 10, {button: 1}, gBrowser.selectedBrowser);
yield middlePagePromise;
is(gBrowser.currentURI.spec, url.replace(/^javascript:/, ""), "url loaded by middle click doesn't include JS");
gBrowser.removeTab(tab);
});

View File

@ -8,70 +8,68 @@ MockFilePicker.init(window);
* TestCase for bug 564387
* <https://bugzilla.mozilla.org/show_bug.cgi?id=564387>
*/
function test() {
waitForExplicitFinish();
add_task(function* () {
var fileName;
let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
gBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/general/web_video.html");
yield loadPromise;
gBrowser.addEventListener("pageshow", function pageShown(event) {
if (event.target.location == "about:blank")
return;
gBrowser.removeEventListener("pageshow", pageShown);
let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown");
executeSoon(function () {
document.addEventListener("popupshown", contextMenuOpened);
yield BrowserTestUtils.synthesizeMouseAtCenter("#video1",
{ type: "contextmenu", button: 2 },
gBrowser.selectedBrowser);
info("context menu click on video1");
var video1 = gBrowser.contentDocument.getElementById("video1");
EventUtils.synthesizeMouseAtCenter(video1,
{ type: "contextmenu", button: 2 },
gBrowser.contentWindow);
info("context menu click on video1");
});
});
yield popupShownPromise;
function contextMenuOpened(event) {
event.currentTarget.removeEventListener("popupshown", contextMenuOpened);
info("context menu opened on video1");
info("context menu opened on video1");
// Create the folder the video will be saved into.
var destDir = createTemporarySaveDirectory();
var destFile = destDir.clone();
// Create the folder the video will be saved into.
var destDir = createTemporarySaveDirectory();
var destFile = destDir.clone();
MockFilePicker.displayDirectory = destDir;
MockFilePicker.showCallback = function(fp) {
fileName = fp.defaultString;
destFile.append (fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};
MockFilePicker.displayDirectory = destDir;
MockFilePicker.showCallback = function(fp) {
fileName = fp.defaultString;
destFile.append(fileName);
MockFilePicker.returnFiles = [destFile];
MockFilePicker.filterIndex = 1; // kSaveAsType_URL
};
let transferCompletePromise = new Promise((resolve) => {
function onTransferComplete(downloadSuccess) {
ok(downloadSuccess, "Video file should have been downloaded successfully");
is(fileName, "web-video1-expectedName.ogv",
"Video file name is correctly retrieved from Content-Disposition http header");
resolve();
}
mockTransferCallback = onTransferComplete;
mockTransferRegisterer.register();
});
registerCleanupFunction(function () {
mockTransferRegisterer.unregister();
MockFilePicker.cleanup();
destDir.remove(true);
});
registerCleanupFunction(function () {
mockTransferRegisterer.unregister();
MockFilePicker.cleanup();
destDir.remove(true);
});
// Select "Save Video As" option from context menu
var saveVideoCommand = document.getElementById("context-savevideo");
saveVideoCommand.doCommand();
info("context-savevideo command executed");
// Select "Save Video As" option from context menu
var saveVideoCommand = document.getElementById("context-savevideo");
saveVideoCommand.doCommand();
info("context-savevideo command executed");
event.target.hidePopup();
}
let contextMenu = document.getElementById("contentAreaContextMenu");
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
contextMenu.hidePopup();
yield popupHiddenPromise;
function onTransferComplete(downloadSuccess) {
ok(downloadSuccess, "Video file should have been downloaded successfully");
yield transferCompletePromise;
});
is(fileName, "web-video1-expectedName.ogv",
"Video file name is correctly retrieved from Content-Disposition http header");
finish();
}
}
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)

View File

@ -1,39 +1,31 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let url = "http://mochi.test:8888/browser/browser/base/content/test/general/test_wyciwyg_copying.html";
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
tab.linkedBrowser.addEventListener("pageshow", function () {
let btn = content.document.getElementById("btn");
executeSoon(function () {
EventUtils.synthesizeMouseAtCenter(btn, {}, content);
let currentURL = gBrowser.currentURI.spec;
ok(/^wyciwyg:\/\//i.test(currentURL), currentURL + " is a wyciwyg URI");
executeSoon(function () {
testURLBarCopy(url, endTest);
});
});
}, false);
function endTest() {
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
finish();
}
function testURLBarCopy(targetValue, cb) {
function testURLBarCopy(targetValue) {
return new Promise((resolve, reject) => {
info("Expecting copy of: " + targetValue);
waitForClipboard(targetValue, function () {
gURLBar.focus();
gURLBar.select();
goDoCommand("cmd_copy");
}, cb, cb);
}
}, resolve, () => {
ok(false, "Clipboard copy failed");
reject();
});
});
}
add_task(function* () {
const url = "http://mochi.test:8888/browser/browser/base/content/test/general/test_wyciwyg_copying.html";
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
yield BrowserTestUtils.synthesizeMouseAtCenter("#btn", {}, tab.linkedBrowser);
let currentURL = gBrowser.currentURI.spec;
ok(/^wyciwyg:\/\//i.test(currentURL), currentURL + " is a wyciwyg URI");
yield testURLBarCopy(url);
while (gBrowser.tabs.length > 1)
gBrowser.removeCurrentTab();
});

View File

@ -34,6 +34,25 @@ function testMalware(event) {
var style = content.getComputedStyle(el, null);
is(style.display, "inline-block", "Ignore Warning button should be display:inline-block for malware");
// Now launch the unwanted software test
window.addEventListener("DOMContentLoaded", testUnwanted, true);
content.location = "http://www.itisatrap.org/firefox/unwanted.html";
}
function testUnwanted(event) {
if (event.target != gBrowser.selectedBrowser.contentDocument) {
return;
}
window.removeEventListener("DOMContentLoaded", testUnwanted, true);
// Confirm that "Ignore this warning" is visible - bug 422410
var el = content.document.getElementById("ignoreWarningButton");
ok(el, "Ignore warning button should be present for unwanted software");
var style = content.getComputedStyle(el, null);
is(style.display, "inline-block", "Ignore Warning button should be display:inline-block for unwanted software");
// Now launch the phishing test
window.addEventListener("DOMContentLoaded", testPhishing, true);
content.location = "http://www.itisatrap.org/firefox/its-a-trap.html";

View File

@ -1,5 +1,5 @@
// Force SafeBrowsing to be initialized for the tests
Services.prefs.setCharPref("urlclassifier.malwareTable", "test-malware-simple");
Services.prefs.setCharPref("urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple");
Services.prefs.setCharPref("urlclassifier.phishTable", "test-phish-simple");
SafeBrowsing.init();

View File

@ -218,6 +218,7 @@
@RESPATH@/components/dom_offline.xpt
@RESPATH@/components/dom_json.xpt
@RESPATH@/components/dom_power.xpt
@RESPATH@/components/dom_push.xpt
@RESPATH@/components/dom_quota.xpt
@RESPATH@/components/dom_range.xpt
@RESPATH@/components/dom_security.xpt
@ -558,7 +559,7 @@
@RESPATH@/components/AlarmsManager.manifest
@RESPATH@/components/Push.js
@RESPATH@/components/Push.manifest
@RESPATH@/components/PushServiceLauncher.js
@RESPATH@/components/PushNotificationService.js
@RESPATH@/components/SlowScriptDebug.manifest
@RESPATH@/components/SlowScriptDebug.js

View File

@ -400,6 +400,7 @@ safebrowsing.notAForgeryButton.accessKey=F
safebrowsing.reportedAttackSite=Reported Attack Site!
safebrowsing.notAnAttackButton.label=This isn't an attack site…
safebrowsing.notAnAttackButton.accessKey=A
safebrowsing.reportedUnwantedSite=Reported Unwanted Software Site!
# Ctrl-Tab
# LOCALIZATION NOTE (ctrlTab.listAllTabs.label): #1 represents the number

View File

@ -12,6 +12,11 @@
<!ENTITY safeb.blocked.malwarePage.shortDesc "This web page at <span id='malware_sitename'/> has been reported as an attack page and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.malwarePage.longDesc "<p>Attack pages try to install programs that steal private information, use your computer to attack others, or damage your system.</p><p>Some attack pages intentionally distribute harmful software, but many are compromised without the knowledge or permission of their owners.</p>">
<!ENTITY safeb.blocked.unwantedPage.title "Reported Unwanted Software Page!">
<!-- Localization note (safeb.blocked.malware.shortDesc) - Please don't translate the contents of the <span id="unwanted_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.unwantedPage.shortDesc "This web page at <span id='unwanted_sitename'/> has been reported to contain unwanted software and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.unwantedPage.longDesc "<p>Unwanted software pages try to install software that can be deceptive and affect your system in unexpected ways.</p>">
<!ENTITY safeb.blocked.phishingPage.title "Reported Web Forgery!">
<!-- Localization note (safeb.blocked.phishing.shortDesc) - Please don't translate the contents of the <span id="phishing_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.phishingPage.shortDesc "This web page at <span id='phishing_sitename'/> has been reported as a web forgery and has been blocked based on your security preferences.">

View File

@ -30,6 +30,7 @@ externalProtocolUnknown=<Unknown>
externalProtocolChkMsg=Remember my choice for all links of this type.
externalProtocolLaunchBtn=Launch application
malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
unwantedBlocked=The site at %S has been reported as serving unwanted software and has been blocked based on your security preferences.
phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.

View File

@ -164,6 +164,11 @@ be temporary, and you can try again later.</li>
<p>Website owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p>
">
<!ENTITY unwantedBlocked.title "Suspected Unwanted Software Site!">
<!ENTITY unwantedBlocked.longDesc "
<p>Unwanted software pages try to install software that can be deceptive and affect your system in unexpected ways.</p>
">
<!ENTITY phishingBlocked.title "Suspected Web Forgery!">
<!ENTITY phishingBlocked.longDesc "
<p>Entering any personal information on this page may result in identity theft or other fraud.</p>

View File

@ -341,20 +341,15 @@ let Content = {
}
} else if (/^about:blocked/.test(errorDoc.documentURI)) {
// The event came from a button on a malware/phishing block page
// First check whether it's malware or phishing, so that we can
// use the right strings/links.
let isMalware = /e=malwareBlocked/.test(errorDoc.documentURI);
if (ot == errorDoc.getElementById("getMeOutButton")) {
sendAsyncMessage("Browser:BlockedSite",
{ url: errorDoc.location.href, action: "leave" });
} else if (ot == errorDoc.getElementById("reportButton")) {
// This is the "Why is this site blocked" button. For malware,
// we can fetch a site-specific report, for phishing, we redirect
// to the generic page describing phishing protection.
let action = isMalware ? "report-malware" : "report-phishing";
// This is the "Why is this site blocked" button. We redirect
// to the generic page describing phishing/malware protection.
sendAsyncMessage("Browser:BlockedSite",
{ url: errorDoc.location.href, action: action });
{ url: errorDoc.location.href, action: "report-phishing" });
} else if (ot == errorDoc.getElementById("ignoreWarningButton")) {
// Allow users to override and continue through to the site,
// but add a notify bar as a reminder, so that they don't lose

View File

@ -9,10 +9,8 @@ scrollbar {
padding: 2px;
}
/* Scrollbar code will reset the margin to the correct side depending on
layout.scrollbar.side pref */
scrollbar[orient="vertical"] {
margin-left: -10px;
-moz-margin-start: -10px;
min-width: 10px;
max-width: 10px;
}

View File

@ -10,10 +10,8 @@ scrollbar {
padding: 2px;
}
/* Scrollbar code will reset the margin to the correct side depending on
layout.scrollbar.side pref */
scrollbar[orient="vertical"] {
margin-left: -8px;
-moz-margin-start: -8px;
min-width: 8px;
max-width: 8px;
}

View File

@ -9,10 +9,8 @@ scrollbar {
padding: 2px;
}
/* Scrollbar code will reset the margin to the correct side depending on
layout.scrollbar.side pref */
scrollbar[orient="vertical"] {
margin-left: -10px;
-moz-margin-start: -10px;
min-width: 10px;
max-width: 10px;
}

View File

@ -101,12 +101,15 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMis
"""Process a single leak log.
"""
# Per-Inst Leaked Total Rem ...
# 0 TOTAL 17 192 419115886 2 ...
# 833 nsTimerImpl 60 120 24726 2 ...
lineRe = re.compile(r"^\s*\d+\s+(?P<name>\S+)\s+"
r"(?P<size>-?\d+)\s+(?P<bytesLeaked>-?\d+)\s+"
r"-?\d+\s+(?P<numLeaked>-?\d+)")
# | |Per-Inst Leaked| Total Rem|
# 0 |TOTAL | 17 192| 419115886 2|
# 833 |nsTimerImpl | 60 120| 24726 2|
# 930 |Foo<Bar, Bar> | 32 8| 100 1|
lineRe = re.compile(r"^\s*\d+ \|"
r"(?P<name>[^|]+)\|"
r"\s*(?P<size>-?\d+)\s+(?P<bytesLeaked>-?\d+)\s*\|"
r"\s*-?\d+\s+(?P<numLeaked>-?\d+)")
# The class name can contain spaces. We remove trailing whitespace later.
processString = "%s process:" % processType
crashedOnPurpose = False
@ -125,7 +128,7 @@ def processSingleLeakFile(leakLogFileName, processType, leakThreshold, ignoreMis
# eg: the leak table header row
log.info(line.rstrip())
continue
name = matches.group("name")
name = matches.group("name").rstrip()
size = int(matches.group("size"))
bytesLeaked = int(matches.group("bytesLeaked"))
numLeaked = int(matches.group("numLeaked"))

View File

@ -84,6 +84,11 @@ private:
virtual void run(const MatchFinder::MatchResult &Result);
};
class ExplicitOperatorBoolChecker : public MatchFinder::MatchCallback {
public:
virtual void run(const MatchFinder::MatchResult &Result);
};
ScopeChecker stackClassChecker;
ScopeChecker globalClassChecker;
NonHeapClassChecker nonheapClassChecker;
@ -92,16 +97,17 @@ private:
NaNExprChecker nanExprChecker;
NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker;
RefCountedInsideLambdaChecker refCountedInsideLambdaChecker;
ExplicitOperatorBoolChecker explicitOperatorBoolChecker;
MatchFinder astMatcher;
};
namespace {
bool isInIgnoredNamespace(const Decl *decl) {
std::string getDeclarationNamespace(const Decl *decl) {
const DeclContext *DC = decl->getDeclContext()->getEnclosingNamespaceContext();
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) {
return false;
return "";
}
while (const DeclContext *ParentDC = ND->getParent()) {
@ -112,8 +118,15 @@ bool isInIgnoredNamespace(const Decl *decl) {
}
const auto& name = ND->getName();
return name;
}
bool isInIgnoredNamespaceForImplicitCtor(const Decl *decl) {
std::string name = getDeclarationNamespace(decl);
if (name == "") {
return false;
}
// namespace std and icu are ignored for now
return name == "std" || // standard C++ lib
name == "__gnu_cxx" || // gnu C++ lib
name == "boost" || // boost
@ -129,7 +142,19 @@ bool isInIgnoredNamespace(const Decl *decl) {
name == "testing"; // gtest
}
bool isIgnoredPath(const Decl *decl) {
bool isInIgnoredNamespaceForImplicitConversion(const Decl *decl) {
std::string name = getDeclarationNamespace(decl);
if (name == "") {
return false;
}
return name == "std" || // standard C++ lib
name == "__gnu_cxx" || // gnu C++ lib
name == "google_breakpad" || // breakpad
name == "testing"; // gtest
}
bool isIgnoredPathForImplicitCtor(const Decl *decl) {
decl = decl->getCanonicalDecl();
SourceLocation Loc = decl->getLocation();
const SourceManager &SM = decl->getASTContext().getSourceManager();
@ -150,9 +175,30 @@ bool isIgnoredPath(const Decl *decl) {
return false;
}
bool isInterestingDecl(const Decl *decl) {
return !isInIgnoredNamespace(decl) &&
!isIgnoredPath(decl);
bool isIgnoredPathForImplicitConversion(const Decl *decl) {
decl = decl->getCanonicalDecl();
SourceLocation Loc = decl->getLocation();
const SourceManager &SM = decl->getASTContext().getSourceManager();
SmallString<1024> FileName = SM.getFilename(Loc);
llvm::sys::fs::make_absolute(FileName);
llvm::sys::path::reverse_iterator begin = llvm::sys::path::rbegin(FileName),
end = llvm::sys::path::rend(FileName);
for (; begin != end; ++begin) {
if (begin->compare_lower(StringRef("graphite2")) == 0) {
return true;
}
}
return false;
}
bool isInterestingDeclForImplicitCtor(const Decl *decl) {
return !isInIgnoredNamespaceForImplicitCtor(decl) &&
!isIgnoredPathForImplicitCtor(decl);
}
bool isInterestingDeclForImplicitConversion(const Decl *decl) {
return !isInIgnoredNamespaceForImplicitConversion(decl) &&
!isIgnoredPathForImplicitConversion(decl);
}
}
@ -232,7 +278,7 @@ public:
}
}
if (!d->isAbstract() && isInterestingDecl(d)) {
if (!d->isAbstract() && isInterestingDeclForImplicitCtor(d)) {
for (CXXRecordDecl::ctor_iterator ctor = d->ctor_begin(),
e = d->ctor_end(); ctor != e; ++ctor) {
// Ignore non-converting ctors
@ -416,6 +462,16 @@ bool isClassRefCounted(QualType T) {
return clazz ? isClassRefCounted(clazz) : RegularClass;
}
template<class T>
bool IsInSystemHeader(const ASTContext &AC, const T &D) {
auto &SourceManager = AC.getSourceManager();
auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart());
if (ExpansionLoc.isInvalid()) {
return false;
}
return SourceManager.isInSystemHeader(ExpansionLoc);
}
}
namespace clang {
@ -515,12 +571,7 @@ AST_MATCHER(QualType, isFloat) {
/// isExpansionInSystemHeader in newer clangs, but modified in order to work
/// with old clangs that we use on infra.
AST_MATCHER(BinaryOperator, isInSystemHeader) {
auto &SourceManager = Finder->getASTContext().getSourceManager();
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
if (ExpansionLoc.isInvalid()) {
return false;
}
return SourceManager.isInSystemHeader(ExpansionLoc);
return IsInSystemHeader(Finder->getASTContext(), Node);
}
/// This matcher will match locations in SkScalar.h. This header contains a
@ -649,6 +700,13 @@ DiagnosticsMatcher::DiagnosticsMatcher()
hasDescendant(declRefExpr(hasType(pointerType(pointee(isRefCounted())))).bind("node"))
),
&refCountedInsideLambdaChecker);
// Older clang versions such as the ones used on the infra recognize these
// conversions as 'operator _Bool', but newer clang versions recognize these
// as 'operator bool'.
astMatcher.addMatcher(methodDecl(anyOf(hasName("operator bool"),
hasName("operator _Bool"))).bind("node"),
&explicitOperatorBoolChecker);
}
void DiagnosticsMatcher::ScopeChecker::run(
@ -861,6 +919,25 @@ void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
Diag.Report(node->getLocStart(), noteID);
}
void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(
const MatchFinder::MatchResult &Result) {
DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Error, "bad implicit conversion operator for %0");
unsigned noteID = Diag.getDiagnosticIDs()->getCustomDiagID(
DiagnosticIDs::Note, "consider adding the explicit keyword to %0");
const CXXConversionDecl *method = Result.Nodes.getNodeAs<CXXConversionDecl>("node");
const CXXRecordDecl *clazz = method->getParent();
if (!method->isExplicitSpecified() &&
!MozChecker::hasCustomAnnotation(method, "moz_implicit") &&
!IsInSystemHeader(method->getASTContext(), *method) &&
isInterestingDeclForImplicitConversion(method)) {
Diag.Report(method->getLocStart(), errorID) << clazz;
Diag.Report(method->getLocStart(), noteID) << "'operator bool'";
}
}
class MozCheckAction : public PluginASTAction {
public:
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override {

View File

@ -0,0 +1,11 @@
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
struct Bad {
operator bool(); // expected-error {{bad implicit conversion operator for 'Bad'}} expected-note {{consider adding the explicit keyword to 'operator bool'}}
};
struct Good {
explicit operator bool();
};
struct Okay {
MOZ_IMPLICIT operator bool();
};

View File

@ -7,6 +7,7 @@
SOURCES += [
'TestBadImplicitConversionCtor.cpp',
'TestCustomHeap.cpp',
'TestExplicitOperatorBool.cpp',
'TestGlobalClass.cpp',
'TestMustOverride.cpp',
'TestNANTestingExpr.cpp',

View File

@ -180,7 +180,13 @@ class RemoteAutomation(Automation):
self.checkForANRs()
self.checkForTombstones()
logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
try:
logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
except DMError:
print "getLogcat threw DMError; re-trying just once..."
time.sleep(1)
logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
javaException = mozcrash.check_for_java_exception(logcat)
if javaException:
return True

View File

@ -8,7 +8,7 @@
# It is referred to by the following page, so if this file moves, that page must
# be modified accordingly:
#
# http://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F
# https://developer.mozilla.org/en/docs/Mochitest#How_do_I_test_issues_which_only_show_up_when_tests_are_run_across_domains.3F
#
# Empty lines and lines which begin with "#" are ignored and may be used for
# storing comments. All other lines consist of an origin followed by whitespace

View File

@ -13,10 +13,6 @@
namespace mozilla {
namespace dom {
class nsIContentParent;
};
namespace ipc {
class URIParams;
};

View File

@ -9,8 +9,6 @@
#include "jsapi.h"
#include "nsIPrincipal.h"
class nsCString;
struct nsJSPrincipals : nsIPrincipal, JSPrincipals
{
static bool Subsume(JSPrincipals *jsprin, JSPrincipals *other);

View File

@ -15,9 +15,6 @@
#include "nsNetUtil.h"
#include "nsScriptSecurityManager.h"
class nsIObjectInputStream;
class nsIObjectOutputStream;
class nsBasePrincipal : public nsJSPrincipals
{
public:

View File

@ -17,13 +17,10 @@
#include <stdint.h>
class nsIDocShell;
class nsCString;
class nsIClassInfo;
class nsIIOService;
class nsIStringBundle;
class nsSystemPrincipal;
class ClassInfoData;
/////////////////////////////
// nsScriptSecurityManager //

View File

@ -3017,6 +3017,7 @@ then
esac
LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
AC_SUBST(MOZ_USE_PTHREADS)
MOZ_CHECK_HEADERS(pthread.h)
fi

View File

@ -10,7 +10,6 @@
#include "nsISupports.h"
class nsIURI;
class nsString;
namespace mozilla {

View File

@ -14,8 +14,6 @@
#include "nsIInterfaceRequestor.h"
#include "nsILoadContext.h"
class mozIApplication;
namespace mozilla {
/**

View File

@ -5087,7 +5087,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
}
}
} else if (NS_ERROR_PHISHING_URI == aError ||
NS_ERROR_MALWARE_URI == aError) {
NS_ERROR_MALWARE_URI == aError ||
NS_ERROR_UNWANTED_URI == aError) {
nsAutoCString host;
aURI->GetHost(host);
CopyUTF8toUTF16(host, formatStrs[0]);
@ -5106,14 +5107,19 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
error.AssignLiteral("phishingBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_PHISHING_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_PHISHING_PAGE_TOP;
} else {
} else if (NS_ERROR_MALWARE_URI == aError) {
error.AssignLiteral("malwareBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_MALWARE_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_MALWARE_PAGE_TOP;
} else {
error.AssignLiteral("unwantedBlocked");
bucketId = IsFrame() ? nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_FRAME
: nsISecurityUITelemetry::WARNING_UNWANTED_PAGE_TOP;
}
if (errorPage.EqualsIgnoreCase("blocked"))
if (errorPage.EqualsIgnoreCase("blocked")) {
Telemetry::Accumulate(Telemetry::SECURITY_UI, bucketId);
}
cssClass.AssignLiteral("blacklist");
} else if (NS_ERROR_CONTENT_CRASHED == aError) {
@ -7824,6 +7830,7 @@ nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
aStatus == NS_ERROR_OFFLINE ||
aStatus == NS_ERROR_MALWARE_URI ||
aStatus == NS_ERROR_PHISHING_URI ||
aStatus == NS_ERROR_UNWANTED_URI ||
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
aStatus == NS_ERROR_REMOTE_XUL ||
aStatus == NS_ERROR_OFFLINE ||

View File

@ -88,7 +88,6 @@ class nsIURIFixup;
class nsIURILoader;
class nsIWebBrowserFind;
class nsIWidget;
class ProfilerMarkerTracing;
/* load commands were moved to nsIDocShell.h */
/* load types were moved to nsDocShellLoadTypes.h */

View File

@ -6,7 +6,9 @@
#include "nsISupports.idl"
[scriptable, uuid(AF13EA3A-D488-4308-B843-526E055AB943)]
interface nsIDOMNode;
[scriptable, uuid(35BE2D7E-F29B-48EC-BF7E-80A30A724DE3)]
interface nsIContentViewerEdit : nsISupports
{
void clearSelection();
@ -27,4 +29,8 @@ interface nsIContentViewerEdit : nsISupports
AString getContents(in string aMimeType, in boolean aSelectionOnly);
readonly attribute boolean canGetContents;
// Set the node that will be the subject of the editing commands above.
// Usually this will be the node that was context-clicked.
void setCommandNode(in nsIDOMNode aNode);
};

View File

@ -13,7 +13,6 @@ class nsIContent;
class nsIDocShell;
class nsIInputStream;
class nsIRequest;
class nsString;
// Interface ID for nsILinkHandler
#define NS_ILINKHANDLER_IID \

View File

@ -291,6 +291,7 @@
<h1 id="et_nssFailure2">&nssFailure2.title;</h1>
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
<h1 id="et_malwareBlocked">&malwareBlocked.title;</h1>
<h1 id="et_unwantedBlocked">&unwantedBlocked.title;</h1>
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
@ -317,6 +318,7 @@
<div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
<div id="ed_malwareBlocked">&malwareBlocked.longDesc;</div>
<div id="ed_unwantedBlocked">&unwantedBlocked.longDesc;</div>
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>

View File

@ -217,6 +217,32 @@ Animation::GetFinished(ErrorResult& aRv)
return mFinished;
}
void
Animation::Finish(ErrorResult& aRv)
{
// https://w3c.github.io/web-animations/#finish-an-animation
if (mPlaybackRate == 0 ||
(mPlaybackRate > 0 && EffectEnd() == TimeDuration::Forever())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
TimeDuration limit =
mPlaybackRate > 0 ? TimeDuration(EffectEnd()) : TimeDuration(0);
SetCurrentTime(limit);
if (mPendingState == PendingState::PlayPending) {
CancelPendingTasks();
if (mReady) {
mReady->MaybeResolve(this);
}
}
UpdateFinishedState(true);
PostUpdate();
}
void
Animation::Play(LimitBehavior aLimitBehavior)
{

View File

@ -94,6 +94,7 @@ public:
AnimationPlayState PlayState() const;
virtual Promise* GetReady(ErrorResult& aRv);
virtual Promise* GetFinished(ErrorResult& aRv);
virtual void Finish(ErrorResult& aRv);
virtual void Play(LimitBehavior aLimitBehavior);
virtual void Pause();
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }

View File

@ -83,112 +83,6 @@ const TEN_PCT_POSITION = 110;
const FIFTY_PCT_POSITION = 150;
const END_POSITION = 200;
/**
* CSS animation events fire asynchronously after we set 'startTime'. This
* helper class allows us to handle such events using Promises.
*
* To use this class:
*
* var eventWatcher = new EventWatcher(watchedNode, eventTypes);
* eventWatcher.waitForEvent(eventType).then(function() {
* // Promise fulfilled
* checkStuff();
* makeSomeChanges();
* return eventWatcher.waitForEvent(nextEventType);
* }).then(function() {
* // Promise fulfilled
* checkMoreStuff();
* eventWatcher.stopWatching(); // all done - stop listening for events
* });
*
* This class will assert_unreached() if an event occurs when there is no
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
* event is of a different type to the type passed to waitForEvent. This helps
* provide test coverage to ensure that only events that are expected occur, in
* the correct order and with the correct timing. It also helps vastly simplify
* the already complex code below by avoiding lots of gnarly error handling
* code.
*/
function EventWatcher(watchedNode, eventTypes)
{
if (typeof eventTypes == 'string') {
eventTypes = [eventTypes];
}
var waitingFor = null;
function eventHandler(evt) {
if (!waitingFor) {
assert_unreached('Not expecting event, but got: ' + evt.type +
' targeting element #' + evt.target.getAttribute('id'));
return;
}
if (evt.type != waitingFor.types[0]) {
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
evt.type + ' event');
return;
}
if (waitingFor.types.length > 1) {
// Pop first event from array
waitingFor.types.shift();
return;
}
// We need to null out waitingFor before calling the resolve function since
// the Promise's resolve handlers may call waitForEvent() which will need
// to set waitingFor.
var resolveFunc = waitingFor.resolve;
waitingFor = null;
resolveFunc(evt);
}
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.addEventListener(eventTypes[i], eventHandler);
}
this.waitForEvent = function(type) {
if (typeof type != 'string') {
return Promise.reject('Event type not a string');
}
return this.waitForEvents([type]);
};
/**
* This is useful when two events are expected to fire one immediately after
* the other. This happens when we skip over the entire active interval for
* instance. In this case an 'animationstart' and an 'animationend' are fired
* and due to the asynchronous nature of Promise callbacks this won't work:
*
* eventWatcher.waitForEvent('animationstart').then(function() {
* return waitForEvent('animationend');
* }).then(...);
*
* It doesn't work because the 'animationend' listener is added too late,
* because the resolve handler for the first Promise is called asynchronously
* some time after the 'animationstart' event is called, rather than at the
* time the event reaches the watched element.
*/
this.waitForEvents = function(types) {
if (waitingFor) {
return Promise.reject('Already waiting for an event');
}
return new Promise(function(resolve, reject) {
waitingFor = {
types: types,
resolve: resolve,
reject: reject
};
});
};
this.stopWatching = function() {
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.removeEventListener(eventTypes[i], eventHandler);
}
};
return this;
}
// The terms used for the naming of the following helper functions refer to
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
@ -336,7 +230,7 @@ test(function(t)
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
@ -347,7 +241,7 @@ async_test(function(t) {
animation.currentTime =
currentTimeForStartOfActiveInterval(animation.timeline);
return eventWatcher.waitForEvent('animationstart');
return eventWatcher.wait_for('animationstart');
})).then(t.step_func(function() {
checkStateAtActiveIntervalStartTime(animation);
@ -357,11 +251,9 @@ async_test(function(t) {
animation.currentTime =
currentTimeForEndOfActiveInterval(animation.timeline);
return eventWatcher.waitForEvent('animationend');
return eventWatcher.wait_for('animationend');
})).then(t.step_func(function() {
checkStateAtActiveIntervalEndTime(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -372,7 +264,7 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
@ -389,8 +281,8 @@ async_test(function(t) {
// an 'animationend' event. We need to wait for these events before we start
// testing going backwards since EventWatcher will fail the test if it gets
// an event that we haven't told it about.
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(t.step_func(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(t.step_func(function() {
assert_true(document.timeline.currentTime - previousTimelineTime <
ANIM_DUR_MS,
'Sanity check that seeking worked rather than the events ' +
@ -410,9 +302,9 @@ async_test(function(t) {
//
// Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
// causing computed style to be updated and the 'animationstart' event to
// be dispatched synchronously. We need to call waitForEvent first
// be dispatched synchronously. We need to call wait_for first
// otherwise eventWatcher will assert that the event was unexpected.
var promise = eventWatcher.waitForEvent('animationstart');
var promise = eventWatcher.wait_for('animationstart');
checkStateAtFiftyPctOfActiveInterval(animation);
return promise;
})).then(t.step_func(function() {
@ -424,11 +316,9 @@ async_test(function(t) {
// Despite going backwards from just after the active interval starts to
// the animation start time, we now expect an animationend event
// because we went from inside to outside the active interval.
return eventWatcher.waitForEvent('animationend');
return eventWatcher.wait_for('animationend');
})).then(t.step_func(function() {
checkStateOnReadyPromiseResolved(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -454,7 +344,7 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
@ -462,14 +352,13 @@ async_test(function(t) {
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
}, 'Redundant change, before -> active, then back');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
@ -477,23 +366,21 @@ async_test(function(t) {
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
}, 'Redundant change, before -> after, then back');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvent('animationstart').then(function() {
eventWatcher.wait_for('animationstart').then(function() {
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
animation.currentTime = currentTimeForActivePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -503,16 +390,15 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvent('animationstart').then(function() {
eventWatcher.wait_for('animationstart').then(function() {
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
animation.currentTime = currentTimeForActivePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -522,17 +408,16 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(function() {
animation.currentTime = currentTimeForBeforePhase(animation.timeline);
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -542,17 +427,16 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(function() {
animation.currentTime = currentTimeForActivePhase(animation.timeline);
animation.currentTime = currentTimeForAfterPhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});

View File

@ -0,0 +1,160 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<div id="log"></div>
<style>
.animated-div {
margin-left: 10px;
}
@keyframes anim {
from { margin-left: 100px; }
to { margin-left: 200px; }
}
</style>
<script>
'use strict';
const ANIM_PROP_VAL = 'anim 100s';
const ANIM_DURATION = 100000; // ms
test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.playbackRate = 0;
var threw = false;
try {
animation.finish();
} catch (e) {
threw = true;
assert_equals(e.name, 'InvalidStateError',
'Exception should be an InvalidStateError exception when ' +
'trying to finish an animation with playbackRate == 0');
}
assert_true(threw,
'Expect InvalidStateError exception trying to finish an ' +
'animation with playbackRate == 0');
}, 'Test exceptions when finishing non-running animation');
test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
div.style.animationIterationCount = 'infinite';
var animation = div.getAnimations()[0];
var threw = false;
try {
animation.finish();
} catch (e) {
threw = true;
assert_equals(e.name, 'InvalidStateError',
'Exception should be an InvalidStateError exception when ' +
'trying to finish an infinite animation');
}
assert_true(threw,
'Expect InvalidStateError exception trying to finish an ' +
'infinite animation');
}, 'Test exceptions when finishing infinite animation');
test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.finish();
assert_equals(animation.currentTime, ANIM_DURATION,
'After finishing, the currentTime should be set to the end ' +
'of the active duration');
}, 'Test finishing of animation');
test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.currentTime = ANIM_DURATION + 1000; // 1s past effect end
animation.finish();
assert_equals(animation.currentTime, ANIM_DURATION,
'After finishing, the currentTime should be set back to the ' +
'end of the active duration');
}, 'Test finishing of animation with a current time past the effect end');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.currentTime = ANIM_DURATION;
animation.finished.then(t.step_func(function() {
animation.playbackRate = -1;
animation.finish();
assert_equals(animation.currentTime, 0,
'After finishing a reversed animation the currentTime ' +
'should be set to zero');
t.done();
}));
}, 'Test finishing of reversed animation');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.currentTime = ANIM_DURATION;
animation.finished.then(t.step_func(function() {
animation.playbackRate = -1;
animation.currentTime = -1000;
animation.finish();
assert_equals(animation.currentTime, 0,
'After finishing a reversed animation the currentTime ' +
'should be set back to zero');
t.done();
}));
}, 'Test finishing of reversed animation with with a current time less ' +
'than zero');
async_test(function(t) {
var div = addDiv(t);
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.pause();
animation.ready.then(t.step_func(function() {
animation.finish();
assert_equals(animation.playState, 'paused',
'The play state of a paused animation should remain ' +
'"paused" even after finish() is called');
t.done();
}));
}, 'Test paused state after finishing of animation');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
div.style.animation = ANIM_PROP_VAL;
var animation = div.getAnimations()[0];
animation.ready.then(t.step_func(function() {
animation.finish();
var marginLeft = parseFloat(getComputedStyle(div).marginLeft);
assert_equals(marginLeft, 10,
'The computed style should be reset when finish() is ' +
'called');
t.done();
}));
}, 'Test resetting of computed style');
</script>

View File

@ -77,7 +77,7 @@ async_test(function(t) {
animation.currentTime = ANIM_DURATION;
animation.finished.then(function() {
animation.finished.then(t.step_func(function() {
previousFinishedPromise = animation.finished;
animation.playbackRate = -1;
assert_not_equals(animation.finished, previousFinishedPromise,
@ -85,7 +85,7 @@ async_test(function(t) {
'finished promise');
animation.currentTime = 0;
return animation.finished;
}).then(t.step_func(function() {
})).then(t.step_func(function() {
previousFinishedPromise = animation.finished;
animation.play();
assert_not_equals(animation.finished, previousFinishedPromise,

View File

@ -44,13 +44,13 @@ async_test(function(t) {
var animation = div.getAnimations()[0];
var originalReadyPromise = animation.ready;
animation.ready.then(function() {
animation.ready.then(t.step_func(function() {
div.style.animationPlayState = 'running';
assert_not_equals(animation.ready, originalReadyPromise,
'After updating animation-play-state a new ready promise'
+ ' object is created');
t.done();
});
}));
}, 'A new ready promise is created when setting animation-play-state: running');
async_test(function(t) {
@ -58,14 +58,14 @@ async_test(function(t) {
div.style.animation = 'abc 100s';
var animation = div.getAnimations()[0];
animation.ready.then(function() {
animation.ready.then(t.step_func(function() {
var promiseBeforeCallingPlay = animation.ready;
animation.play();
assert_equals(animation.ready, promiseBeforeCallingPlay,
'Ready promise has same object identity after redundant call'
+ ' to play()');
t.done();
});
}));
}, 'Redundant calls to play() do not generate new ready promise objects');
async_test(function(t) {
@ -73,12 +73,12 @@ async_test(function(t) {
div.style.animation = 'abc 100s';
var animation = div.getAnimations()[0];
animation.ready.then(function(resolvedAnimation) {
animation.ready.then(t.step_func(function(resolvedAnimation) {
assert_equals(resolvedAnimation, animation,
'Object identity of Animation passed to Promise callback'
+ ' matches the Animation object owning the Promise');
t.done();
});
}));
}, 'The ready promise is fulfilled with its Animation');
async_test(function(t) {

View File

@ -83,112 +83,6 @@ const TEN_PCT_POSITION = 110;
const FIFTY_PCT_POSITION = 150;
const END_POSITION = 200;
/**
* CSS animation events fire asynchronously after we set 'startTime'. This
* helper class allows us to handle such events using Promises.
*
* To use this class:
*
* var eventWatcher = new EventWatcher(watchedNode, eventTypes);
* eventWatcher.waitForEvent(eventType).then(function() {
* // Promise fulfilled
* checkStuff();
* makeSomeChanges();
* return eventWatcher.waitForEvent(nextEventType);
* }).then(function() {
* // Promise fulfilled
* checkMoreStuff();
* eventWatcher.stopWatching(); // all done - stop listening for events
* });
*
* This class will assert_unreached() if an event occurs when there is no
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
* event is of a different type to the type passed to waitForEvent. This helps
* provide test coverage to ensure that only events that are expected occur, in
* the correct order and with the correct timing. It also helps vastly simplify
* the already complex code below by avoiding lots of gnarly error handling
* code.
*/
function EventWatcher(watchedNode, eventTypes)
{
if (typeof eventTypes == 'string') {
eventTypes = [eventTypes];
}
var waitingFor = null;
function eventHandler(evt) {
if (!waitingFor) {
assert_unreached('Not expecting event, but got: ' + evt.type +
' targeting element #' + evt.target.getAttribute('id'));
return;
}
if (evt.type != waitingFor.types[0]) {
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
evt.type + ' event');
return;
}
if (waitingFor.types.length > 1) {
// Pop first event from array
waitingFor.types.shift();
return;
}
// We need to null out waitingFor before calling the resolve function since
// the Promise's resolve handlers may call waitForEvent() which will need
// to set waitingFor.
var resolveFunc = waitingFor.resolve;
waitingFor = null;
resolveFunc(evt);
}
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.addEventListener(eventTypes[i], eventHandler);
}
this.waitForEvent = function(type) {
if (typeof type != 'string') {
return Promise.reject('Event type not a string');
}
return this.waitForEvents([type]);
};
/**
* This is useful when two events are expected to fire one immediately after
* the other. This happens when we skip over the entire active interval for
* instance. In this case an 'animationstart' and an 'animationend' are fired
* and due to the asynchronous nature of Promise callbacks this won't work:
*
* eventWatcher.waitForEvent('animationstart').then(function() {
* return waitForEvent('animationend');
* }).then(...);
*
* It doesn't work because the 'animationend' listener is added too late,
* because the resolve handler for the first Promise is called asynchronously
* some time after the 'animationstart' event is called, rather than at the
* time the event reaches the watched element.
*/
this.waitForEvents = function(types) {
if (waitingFor) {
return Promise.reject('Already waiting for an event');
}
return new Promise(function(resolve, reject) {
waitingFor = {
types: types,
resolve: resolve,
reject: reject
};
});
};
this.stopWatching = function() {
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.removeEventListener(eventTypes[i], eventHandler);
}
};
return this;
}
// The terms used for the naming of the following helper functions refer to
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
@ -390,7 +284,7 @@ test(function(t)
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
@ -400,7 +294,7 @@ async_test(function(t) {
checkStateOnReadyPromiseResolved(animation);
animation.startTime = startTimeForStartOfActiveInterval(animation.timeline);
return eventWatcher.waitForEvent('animationstart');
return eventWatcher.wait_for('animationstart');
})).then(t.step_func(function() {
checkStateAtActiveIntervalStartTime(animation);
@ -409,11 +303,9 @@ async_test(function(t) {
checkStateAtFiftyPctOfActiveInterval(animation);
animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
return eventWatcher.waitForEvent('animationend');
return eventWatcher.wait_for('animationend');
})).then(t.step_func(function() {
checkStateAtActiveIntervalEndTime(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -424,7 +316,7 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
@ -438,8 +330,8 @@ async_test(function(t) {
// an 'animationend' event. We need to wait for these events before we start
// testing going backwards since EventWatcher will fail the test if it gets
// an event that we haven't told it about.
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(t.step_func(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(t.step_func(function() {
assert_true(document.timeline.currentTime - previousTimelineTime <
ANIM_DUR_MS,
'Sanity check that seeking worked rather than the events ' +
@ -459,9 +351,9 @@ async_test(function(t) {
//
// Calling checkStateAtFiftyPctOfActiveInterval will check computed style,
// causing computed style to be updated and the 'animationstart' event to
// be dispatched synchronously. We need to call waitForEvent first
// be dispatched synchronously. We need to call wait_for first
// otherwise eventWatcher will assert that the event was unexpected.
var promise = eventWatcher.waitForEvent('animationstart');
var promise = eventWatcher.wait_for('animationstart');
checkStateAtFiftyPctOfActiveInterval(animation);
return promise;
})).then(t.step_func(function() {
@ -472,11 +364,9 @@ async_test(function(t) {
// Despite going backwards from just after the active interval starts to
// the animation start time, we now expect an animationend event
// because we went from inside to outside the active interval.
return eventWatcher.waitForEvent('animationend');
return eventWatcher.wait_for('animationend');
})).then(t.step_func(function() {
checkStateOnReadyPromiseResolved(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -502,7 +392,7 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
@ -510,14 +400,13 @@ async_test(function(t) {
animation.startTime = startTimeForBeforePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
}, 'Redundant change, before -> active, then back');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
@ -525,23 +414,21 @@ async_test(function(t) {
animation.startTime = startTimeForBeforePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
}, 'Redundant change, before -> after, then back');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvent('animationstart').then(function() {
eventWatcher.wait_for('animationstart').then(function() {
animation.startTime = startTimeForBeforePhase(animation.timeline);
animation.startTime = startTimeForActivePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -551,16 +438,15 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvent('animationstart').then(function() {
eventWatcher.wait_for('animationstart').then(function() {
animation.startTime = startTimeForAfterPhase(animation.timeline);
animation.startTime = startTimeForActivePhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -570,17 +456,16 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(function() {
animation.startTime = startTimeForBeforePhase(animation.timeline);
animation.startTime = startTimeForAfterPhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -590,17 +475,16 @@ async_test(function(t) {
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
var eventWatcher = new EventWatcher(t, div, CSS_ANIM_EVENTS);
div.style.animation = ANIM_PROPERTY_VAL;
var animation = div.getAnimations()[0];
eventWatcher.waitForEvents(['animationstart',
'animationend']).then(function() {
eventWatcher.wait_for(['animationstart',
'animationend']).then(function() {
animation.startTime = startTimeForActivePhase(animation.timeline);
animation.startTime = startTimeForAfterPhase(animation.timeline);
waitForAnimationFrames(2).then(function() {
eventWatcher.stopWatching();
t.done();
});
});
@ -623,11 +507,11 @@ async_test(function(t) {
return animation.ready;
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
})).then(t.step_func(function() {
assert_equals(animation.currentTime, storedCurrentTime,
'Test that hold time is correct');
t.done();
});
}));
}, 'Setting startTime to null');

View File

@ -73,111 +73,6 @@ const TEN_PCT_POSITION = 110;
const FIFTY_PCT_POSITION = 150;
const END_POSITION = 200;
/**
* CSS animation events fire asynchronously after we set 'startTime'. This
* helper class allows us to handle such events using Promises.
*
* To use this class:
*
* var eventWatcher = new EventWatcher(watchedNode, eventTypes);
* eventWatcher.waitForEvent(eventType).then(function() {
* // Promise fulfilled
* checkStuff();
* makeSomeChanges();
* return eventWatcher.waitForEvent(nextEventType);
* }).then(function() {
* // Promise fulfilled
* checkMoreStuff();
* eventWatcher.stopWatching(); // all done - stop listening for events
* });
*
* This class will assert_unreached() if an event occurs when there is no
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
* event is of a different type to the type passed to waitForEvent. This helps
* provide test coverage to ensure that only events that are expected occur, in
* the correct order and with the correct timing. It also helps vastly simplify
* the already complex code below by avoiding lots of gnarly error handling
* code.
*/
function EventWatcher(watchedNode, eventTypes)
{
if (typeof eventTypes == 'string') {
eventTypes = [eventTypes];
}
var waitingFor = null;
function eventHandler(evt) {
if (!waitingFor) {
assert_unreached('Not expecting event, but got: ' + evt.type +
' targeting element #' + evt.target.getAttribute('id'));
return;
}
if (evt.type != waitingFor.types[0]) {
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
evt.type + ' event');
return;
}
if (waitingFor.types.length > 1) {
// Pop first event from array
waitingFor.types.shift();
return;
}
// We need to null out waitingFor before calling the resolve function since
// the Promise's resolve handlers may call waitForEvent() which will need
// to set waitingFor.
var resolveFunc = waitingFor.resolve;
waitingFor = null;
resolveFunc(evt);
}
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.addEventListener(eventTypes[i], eventHandler);
}
this.waitForEvent = function(type) {
if (typeof type != 'string') {
return Promise.reject('Event type not a string');
}
return this.waitForEvents([type]);
};
/**
* This is useful when two events are expected to fire one immediately after
* the other. This happens when we skip over the entire active interval for
* instance. In this case an 'animationstart' and an 'animationend' are fired
* and due to the asynchronous nature of Promise callbacks this won't work:
*
* eventWatcher.waitForEvent('animationstart').then(function() {
* return waitForEvent('animationend');
* }).then(...);
*
* It doesn't work because the 'animationend' listener is added too late,
* because the resolve handler for the first Promise is called asynchronously
* some time after the 'animationstart' event is called, rather than at the
* time the event reaches the watched element.
*/
this.waitForEvents = function(types) {
if (waitingFor) {
return Promise.reject('Already waiting for an event');
}
return new Promise(function(resolve, reject) {
waitingFor = {
types: types,
resolve: resolve,
reject: reject
};
});
};
this.stopWatching = function() {
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.removeEventListener(eventTypes[i], eventHandler);
}
};
return this;
}
// The terms used for the naming of the following helper functions refer to
// terms used in the Web Animations specification for specific phases of an
@ -300,7 +195,7 @@ test(function(t)
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, 'transitionend');
var eventWatcher = new EventWatcher(t, div, 'transitionend');
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
@ -317,11 +212,9 @@ async_test(function(t) {
checkStateAtFiftyPctOfActiveInterval(animation);
animation.currentTime = currentTimeForEndOfActiveInterval();
return eventWatcher.waitForEvent('transitionend');
return eventWatcher.wait_for('transitionend');
})).then(t.step_func(function() {
checkStateAtActiveIntervalEndTime(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -332,7 +225,7 @@ async_test(function(t) {
test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, 'transitionend');
var eventWatcher = new EventWatcher(t, div, 'transitionend');
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
@ -356,10 +249,9 @@ test(function(t) {
//
// Calling checkStateAtActiveIntervalStartTime will check computed style,
// causing computed style to be updated and the 'transitionend' event to
// be dispatched synchronously. We need to call waitForEvent first
// be dispatched synchronously. We need to call wait_for first
// otherwise eventWatcher will assert that the event was unexpected.
eventWatcher.waitForEvent('transitionend').then(function() {
eventWatcher.stopWatching();
eventWatcher.wait_for('transitionend').then(function() {
t.done();
});
checkStateAtActiveIntervalStartTime(animation);

View File

@ -0,0 +1,61 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<div id="log"></div>
<style>
.animated-div {
margin-left: 100px;
transition: margin-left 1000s linear 1000s;
}
</style>
<script>
'use strict';
const ANIM_DELAY_MS = 1000000; // 1000s
const ANIM_DUR_MS = 1000000; // 1000s
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
var animation = div.getAnimations()[0];
animation.finish();
animation.finished.then(t.step_func(function() {
animation.play();
assert_equals(animation.currentTime, 0,
'Replaying a finished transition should reset its ' +
'currentTime');
t.done();
}));
}, 'Test restarting a finished transition');
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
var animation = div.getAnimations()[0];
animation.ready.then(function() {
animation.playbackRate = -1;
return animation.finished;
}).then(t.step_func(function() {
animation.play();
// FIXME: once animation.effect.computedTiming.endTime is available (bug
// 1108055) we should use that here.
assert_equals(animation.currentTime, ANIM_DELAY_MS + ANIM_DUR_MS,
'Replaying a finished reversed transition should reset ' +
'its currentTime to the end of the effect');
t.done();
}));
}, 'Test restarting a reversed finished transition');
</script>

View File

@ -73,112 +73,6 @@ const TEN_PCT_POSITION = 110;
const FIFTY_PCT_POSITION = 150;
const END_POSITION = 200;
/**
* CSS animation events fire asynchronously after we set 'startTime'. This
* helper class allows us to handle such events using Promises.
*
* To use this class:
*
* var eventWatcher = new EventWatcher(watchedNode, eventTypes);
* eventWatcher.waitForEvent(eventType).then(function() {
* // Promise fulfilled
* checkStuff();
* makeSomeChanges();
* return eventWatcher.waitForEvent(nextEventType);
* }).then(function() {
* // Promise fulfilled
* checkMoreStuff();
* eventWatcher.stopWatching(); // all done - stop listening for events
* });
*
* This class will assert_unreached() if an event occurs when there is no
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
* event is of a different type to the type passed to waitForEvent. This helps
* provide test coverage to ensure that only events that are expected occur, in
* the correct order and with the correct timing. It also helps vastly simplify
* the already complex code below by avoiding lots of gnarly error handling
* code.
*/
function EventWatcher(watchedNode, eventTypes)
{
if (typeof eventTypes == 'string') {
eventTypes = [eventTypes];
}
var waitingFor = null;
function eventHandler(evt) {
if (!waitingFor) {
assert_unreached('Not expecting event, but got: ' + evt.type +
' targeting element #' + evt.target.getAttribute('id'));
return;
}
if (evt.type != waitingFor.types[0]) {
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
evt.type + ' event');
return;
}
if (waitingFor.types.length > 1) {
// Pop first event from array
waitingFor.types.shift();
return;
}
// We need to null out waitingFor before calling the resolve function since
// the Promise's resolve handlers may call waitForEvent() which will need
// to set waitingFor.
var resolveFunc = waitingFor.resolve;
waitingFor = null;
resolveFunc(evt);
}
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.addEventListener(eventTypes[i], eventHandler);
}
this.waitForEvent = function(type) {
if (typeof type != 'string') {
return Promise.reject('Event type not a string');
}
return this.waitForEvents([type]);
};
/**
* This is useful when two events are expected to fire one immediately after
* the other. This happens when we skip over the entire active interval for
* instance. In this case an 'animationstart' and an 'animationend' are fired
* and due to the asynchronous nature of Promise callbacks this won't work:
*
* eventWatcher.waitForEvent('animationstart').then(function() {
* return waitForEvent('animationend');
* }).then(...);
*
* It doesn't work because the 'animationend' listener is added too late,
* because the resolve handler for the first Promise is called asynchronously
* some time after the 'animationstart' event is called, rather than at the
* time the event reaches the watched element.
*/
this.waitForEvents = function(types) {
if (waitingFor) {
return Promise.reject('Already waiting for an event');
}
return new Promise(function(resolve, reject) {
waitingFor = {
types: types,
resolve: resolve,
reject: reject
};
});
};
this.stopWatching = function() {
for (var i = 0; i < eventTypes.length; i++) {
watchedNode.removeEventListener(eventTypes[i], eventHandler);
}
};
return this;
}
// The terms used for the naming of the following helper functions refer to
// terms used in the Web Animations specification for specific phases of an
// animation. The terms can be found here:
@ -277,7 +171,7 @@ test(function(t)
async_test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, 'transitionend');
var eventWatcher = new EventWatcher(t, div, 'transitionend');
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
@ -295,11 +189,9 @@ async_test(function(t) {
checkStateAtFiftyPctOfActiveInterval(animation);
animation.startTime = startTimeForEndOfActiveInterval(animation.timeline);
return eventWatcher.waitForEvent('transitionend');
return eventWatcher.wait_for('transitionend');
})).then(t.step_func(function() {
checkStateAtActiveIntervalEndTime(animation);
eventWatcher.stopWatching();
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
@ -310,7 +202,7 @@ async_test(function(t) {
test(function(t) {
var div = addDiv(t, {'class': 'animated-div'});
var eventWatcher = new EventWatcher(div, 'transitionend');
var eventWatcher = new EventWatcher(t, div, 'transitionend');
flushComputedStyle(div);
div.style.marginLeft = '200px'; // initiate transition
@ -336,8 +228,7 @@ test(function(t) {
// causing computed style to be updated and the 'transitionend' event to
// be dispatched synchronously. We need to call waitForEvent first
// otherwise eventWatcher will assert that the event was unexpected.
eventWatcher.waitForEvent('transitionend').then(function() {
eventWatcher.stopWatching();
eventWatcher.wait_for('transitionend').then(function() {
t.done();
});
checkStateAtActiveIntervalStartTime(animation);
@ -360,11 +251,11 @@ async_test(function(t) {
return animation.ready;
})).catch(t.step_func(function(reason) {
assert_unreached(reason);
})).then(function() {
})).then(t.step_func(function() {
assert_equals(animation.currentTime, storedCurrentTime,
'Test that hold time is correct');
t.done();
});
}));
}, 'Setting startTime to null');

View File

@ -3,9 +3,10 @@ support-files =
testcommon.js
[css-animations/test_animations-dynamic-changes.html]
[css-animations/test_animation-pausing.html]
[css-animations/test_animation-currenttime.html]
[css-animations/test_animation-finish.html]
[css-animations/test_animation-finished.html]
[css-animations/test_animation-pausing.html]
[css-animations/test_animation-playstate.html]
[css-animations/test_animation-ready.html]
[css-animations/test_animation-starttime.html]
@ -13,8 +14,9 @@ support-files =
[css-animations/test_effect-target.html]
[css-animations/test_element-get-animations.html]
skip-if = buildapp == 'mulet'
[css-transitions/test_animation-pausing.html]
[css-transitions/test_animation-currenttime.html]
[css-transitions/test_animation-finished.html]
[css-transitions/test_animation-pausing.html]
[css-transitions/test_animation-ready.html]
[css-transitions/test_animation-starttime.html]
[css-transitions/test_effect-name.html]

View File

@ -10,8 +10,6 @@
#include "nscore.h"
class nsIContent;
class nsIDocument;
class nsINode;
class nsAString;
class nsAttrValue;
class nsTextNode;

View File

@ -37,16 +37,11 @@
#include "mozilla/dom/ElementBinding.h"
#include "Units.h"
class nsIDOMEventListener;
class nsIFrame;
class nsIDOMMozNamedAttrMap;
class nsIDOMCSSStyleDeclaration;
class nsIURI;
class nsIControllers;
class nsEventChainVisitor;
class nsIScrollableFrame;
class nsAttrValueOrString;
class ContentUnbinder;
class nsContentList;
class nsDOMSettableTokenList;
class nsDOMTokenList;

View File

@ -29,10 +29,8 @@
#include "nsWrapperCache.h"
#include "nsWeakReference.h"
class nsDOMMultipartFile;
class nsIFile;
class nsIInputStream;
class nsIClassInfo;
#define FILEIMPL_IID \
{ 0xbccb3275, 0x6778, 0x4ac5, \

View File

@ -49,7 +49,6 @@
#include "nsURIHashKey.h"
class nsIDocument;
class nsIChannel;
class nsIPrincipal;
class nsINode;
class AutoError;

View File

@ -15,10 +15,7 @@
class nsIAtom;
class nsIContent;
class nsIDocument;
class nsPIDOMWindow;
class nsXBLPrototypeBinding;
class nsTagNameMapEntry;
namespace mozilla {
namespace dom {

View File

@ -12,8 +12,6 @@
#include "mozilla/Attributes.h"
class nsIURI;
class nsIChannel;
class nsIDOMWindow;
class ThirdPartyUtil final : public mozIThirdPartyUtil
{

View File

@ -11,8 +11,6 @@
#include "nsAutoPtr.h"
#include "nsString.h"
class nsIDOMBlob;
class nsIPrincipal;
class nsISupports;
class nsIURI;

View File

@ -28,10 +28,6 @@ class nsIInputStream;
namespace mozilla {
namespace dom {
namespace workers {
class WorkerPrivate;
}
class File;
class WebSocketImpl;

View File

@ -12,15 +12,11 @@
#include "nsIDOMEventListener.h"
#include "nsITransferable.h"
class nsIDOMNode;
class nsPIDOMWindow;
class nsIDOMDragEvent;
class nsISelection;
class nsITransferable;
class nsIContent;
class nsIURI;
class nsIFile;
class nsISimpleEnumerator;
namespace mozilla {
namespace dom {

View File

@ -15,10 +15,8 @@
* (mozilla/content and mozilla/layout).
*/
class nsAString;
class nsIContent;
class imgRequestProxy;
class nsNodeInfoManager;
class nsGenericHTMLElement;
namespace mozilla {

View File

@ -31,11 +31,9 @@ class nsIDocument;
class nsIURI;
class nsIChannel;
class nsIDocShell;
class nsIParser;
class nsIAtom;
class nsIChannel;
class nsIContent;
class nsViewManager;
class nsNodeInfoManager;
class nsScriptLoader;
class nsIApplicationCache;

View File

@ -7303,24 +7303,25 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
RefPtr<mozilla::gfx::SourceSurface> surface =
image->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE);
if (surface) {
mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
surface->GetDataSurface();
size_t length;
int32_t stride;
mozilla::UniquePtr<char[]> surfaceData =
nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = nsCString(flavorStr);
item->data() = nsCString(surfaceData.get(), length);
mozilla::RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
surface->GetDataSurface();
size_t length;
int32_t stride;
mozilla::UniquePtr<char[]> surfaceData =
nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
item->flavor() = nsCString(flavorStr);
item->data() = nsCString(surfaceData.get(), length);
IPCDataTransferImage& imageDetails = item->imageDetails();
mozilla::gfx::IntSize size = dataSurface->GetSize();
imageDetails.width() = size.width;
imageDetails.height() = size.height;
imageDetails.stride() = stride;
imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
IPCDataTransferImage& imageDetails = item->imageDetails();
mozilla::gfx::IntSize size = dataSurface->GetSize();
imageDetails.width() = size.width;
imageDetails.height() = size.height;
imageDetails.stride() = stride;
imageDetails.format() = static_cast<uint8_t>(dataSurface->GetFormat());
}
continue;
}

View File

@ -51,18 +51,14 @@ class nsIConsoleService;
class nsIContent;
class nsIContentPolicy;
class nsIContentSecurityPolicy;
class nsIDocShell;
class nsIDocument;
class nsIDocumentLoaderFactory;
class nsIDocumentObserver;
class nsIDOMDocument;
class nsIDOMDocumentFragment;
class nsIDOMEvent;
class nsIDOMHTMLFormElement;
class nsIDOMHTMLInputElement;
class nsIDOMKeyEvent;
class nsIDOMNode;
class nsIDOMScriptObjectFactory;
class nsIDOMWindow;
class nsIDragSession;
class nsIEditor;
@ -71,7 +67,6 @@ class nsIFrame;
class nsIImageLoadingContent;
class nsIInterfaceRequestor;
class nsIIOService;
class nsIJSRuntimeService;
class nsILineBreaker;
class nsIMessageBroadcaster;
class nsNameSpaceManager;
@ -83,7 +78,6 @@ class nsIPrincipal;
class nsIRequest;
class nsIRunnable;
class nsIScriptContext;
class nsIScriptGlobalObject;
class nsIScriptSecurityManager;
class nsIStringBundle;
class nsIStringBundleService;
@ -96,7 +90,6 @@ class nsIXPConnect;
class nsNodeInfoManager;
class nsPIDOMWindow;
class nsPresContext;
class nsScriptObjectTracer;
class nsStringBuffer;
class nsStringHashKey;
class nsTextFragment;

View File

@ -18,11 +18,8 @@
#undef GetClassName
#endif
class nsContentList;
class nsDocument;
struct nsGlobalNameStruct;
class nsGlobalWindow;
class nsIScriptSecurityManager;
struct nsDOMClassInfoData;

View File

@ -64,6 +64,13 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord,
// Observer
bool
nsMutationReceiverBase::IsObservable(nsIContent* aContent)
{
return !aContent->ChromeOnlyAccess() &&
(Observer()->IsChrome() || !aContent->IsInAnonymousSubtree());
}
NS_IMPL_ADDREF(nsMutationReceiver)
NS_IMPL_RELEASE(nsMutationReceiver)
@ -111,8 +118,7 @@ nsMutationReceiver::AttributeWillChange(nsIDocument* aDocument,
int32_t aModType)
{
if (nsAutoMutationBatch::IsBatching() ||
!ObservesAttr(aElement, aNameSpaceID, aAttribute) ||
aElement->ChromeOnlyAccess()) {
!ObservesAttr(RegisterTarget(), aElement, aNameSpaceID, aAttribute)) {
return;
}
@ -147,14 +153,16 @@ nsMutationReceiver::CharacterDataWillChange(nsIDocument *aDocument,
CharacterDataChangeInfo* aInfo)
{
if (nsAutoMutationBatch::IsBatching() ||
!CharacterData() || !(Subtree() || aContent == Target()) ||
aContent->ChromeOnlyAccess()) {
!CharacterData() ||
(!Subtree() && aContent != Target()) ||
(Subtree() && RegisterTarget()->SubtreeRoot() != aContent->SubtreeRoot()) ||
!IsObservable(aContent)) {
return;
}
nsDOMMutationRecord* m =
Observer()->CurrentRecord(nsGkAtoms::characterData);
NS_ASSERTION(!m->mTarget || m->mTarget == aContent,
"Wrong target!");
@ -173,8 +181,11 @@ nsMutationReceiver::ContentAppended(nsIDocument* aDocument,
int32_t aNewIndexInContainer)
{
nsINode* parent = NODE_FROM(aContainer, aDocument);
bool wantsChildList = ChildList() && (Subtree() || parent == Target());
if (!wantsChildList || aFirstNewContent->ChromeOnlyAccess()) {
bool wantsChildList =
ChildList() &&
((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) ||
parent == Target());
if (!wantsChildList || !IsObservable(aFirstNewContent)) {
return;
}
@ -211,8 +222,11 @@ nsMutationReceiver::ContentInserted(nsIDocument* aDocument,
int32_t aIndexInContainer)
{
nsINode* parent = NODE_FROM(aContainer, aDocument);
bool wantsChildList = ChildList() && (Subtree() || parent == Target());
if (!wantsChildList || aChild->ChromeOnlyAccess()) {
bool wantsChildList =
ChildList() &&
((Subtree() && RegisterTarget()->SubtreeRoot() == parent->SubtreeRoot()) ||
parent == Target());
if (!wantsChildList || !IsObservable(aChild)) {
return;
}
@ -243,11 +257,14 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
if (aChild->ChromeOnlyAccess()) {
if (!IsObservable(aChild)) {
return;
}
nsINode* parent = NODE_FROM(aContainer, aDocument);
if (Subtree() && parent->SubtreeRoot() != RegisterTarget()->SubtreeRoot()) {
return;
}
if (nsAutoMutationBatch::IsBatching()) {
if (nsAutoMutationBatch::IsRemovalDone()) {
// This can happen for example if HTML parser parses to
@ -265,7 +282,7 @@ nsMutationReceiver::ContentRemoved(nsIDocument* aDocument,
}
return;
}
}
if (Subtree()) {
// Try to avoid creating transient observer if the node
@ -714,8 +731,9 @@ nsDOMMutationObserver::Constructor(const mozilla::dom::GlobalObject& aGlobal,
return nullptr;
}
MOZ_ASSERT(window->IsInnerWindow());
bool isChrome = nsContentUtils::IsChromeDoc(window->GetExtantDoc());
nsRefPtr<nsDOMMutationObserver> observer =
new nsDOMMutationObserver(window.forget(), aCb);
new nsDOMMutationObserver(window.forget(), aCb, isChrome);
return observer.forget();
}

View File

@ -248,14 +248,20 @@ protected:
mRegisterTarget->OwnerDoc()->SetMayHaveDOMMutationObservers();
}
bool ObservesAttr(mozilla::dom::Element* aElement,
bool IsObservable(nsIContent* aContent);
bool ObservesAttr(nsINode* aRegisterTarget,
mozilla::dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttr)
{
if (mParent) {
return mParent->ObservesAttr(aElement, aNameSpaceID, aAttr);
return mParent->ObservesAttr(aRegisterTarget, aElement, aNameSpaceID, aAttr);
}
if (!Attributes() || (!Subtree() && aElement != Target())) {
if (!Attributes() ||
(!Subtree() && aElement != Target()) ||
(Subtree() && aRegisterTarget->SubtreeRoot() != aElement->SubtreeRoot()) ||
!IsObservable(aElement)) {
return false;
}
if (AllAttributes()) {
@ -447,9 +453,10 @@ class nsDOMMutationObserver final : public nsISupports,
{
public:
nsDOMMutationObserver(already_AddRefed<nsPIDOMWindow>&& aOwner,
mozilla::dom::MutationCallback& aCb)
mozilla::dom::MutationCallback& aCb,
bool aChrome)
: mOwner(aOwner), mLastPendingMutation(nullptr), mPendingMutationCount(0),
mCallback(&aCb), mWaitingForRun(false), mId(++sCount)
mCallback(&aCb), mWaitingForRun(false), mIsChrome(aChrome), mId(++sCount)
{
}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -471,6 +478,11 @@ public:
return mOwner;
}
bool IsChrome()
{
return mIsChrome;
}
void Observe(nsINode& aTarget,
const mozilla::dom::MutationObserverInit& aOptions,
mozilla::ErrorResult& aRv);
@ -571,6 +583,7 @@ protected:
nsRefPtr<mozilla::dom::MutationCallback> mCallback;
bool mWaitingForRun;
bool mIsChrome;
uint64_t mId;

Some files were not shown because too many files have changed in this diff Show More