зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team
This commit is contained in:
Коммит
0a02be2b61
|
@ -12,7 +12,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
|
|
|
@ -12,7 +12,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "e11cf4c78874de3469c4f338cf275aeae31854ee",
|
||||
"revision": "aa1e2bec7aab191896988cee73e8bfb332b894cf",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -11,7 +11,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -10,7 +10,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -12,7 +12,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -11,7 +11,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="788d9ce293a9b44f64536130cf4ad577e8101dbe"/>
|
||||
|
|
|
@ -11,7 +11,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="260effa7f342db418b8d5a95dc61c6e8dd8d09f4"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="d15809c5db9f57869d2119aebf7c5bfb1908cf49"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="49c722fa1a5e1873fa0010829fd97d0b74009ca5"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
malformedURI=The URL is not valid and cannot be loaded.
|
||||
fileNotFound=Firefox can't find the file at %S.
|
||||
dnsNotFound=Firefox can't find the server at %S.
|
||||
protocolNotFound=Firefox doesn't know how to open this address, because the protocol (%S) isn't associated with any program.
|
||||
unknownProtocolFound=Firefox doesn't know how to open this address, because one of the following protocols (%S) isn't associated with any program or is not allowed in this context.
|
||||
connectionFailure=Firefox can't establish a connection to the server at %S.
|
||||
netInterrupt=The connection to %S was interrupted while the page was loading.
|
||||
netTimeout=The server at %S is taking too long to respond.
|
||||
|
|
|
@ -479,7 +479,7 @@ pref("browser.bookmarks.autoExportHTML", false);
|
|||
// keep in {PROFILEDIR}/bookmarkbackups. Special values:
|
||||
// -1: unlimited
|
||||
// 0: no backups created (and deletes all existing backups)
|
||||
pref("browser.bookmarks.max_backups", 10);
|
||||
pref("browser.bookmarks.max_backups", 15);
|
||||
|
||||
// Scripts & Windows prefs
|
||||
pref("dom.disable_open_during_load", true);
|
||||
|
|
|
@ -82,16 +82,20 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
|
||||
"resource:///modules/AsyncShutdown.jsm");
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
// We try to backup bookmarks at idle times, to avoid doing that at shutdown.
|
||||
// Number of idle seconds before trying to backup bookmarks. 10 minutes.
|
||||
const BOOKMARKS_BACKUP_IDLE_TIME = 10 * 60;
|
||||
// Minimum interval in milliseconds between backups.
|
||||
const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
|
||||
// Maximum number of backups to create. Old ones will be purged.
|
||||
const BOOKMARKS_BACKUP_MAX_BACKUPS = 10;
|
||||
// Seconds of idle before trying to create a bookmarks backup.
|
||||
const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 10 * 60;
|
||||
// Minimum interval between backups. We try to not create more than one backup
|
||||
// per interval.
|
||||
const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
|
||||
// Maximum interval between backups. If the last backup is older than these
|
||||
// days we will try to create a new one more aggressively.
|
||||
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 5;
|
||||
|
||||
// Factory object
|
||||
const BrowserGlueServiceFactory = {
|
||||
|
@ -134,7 +138,6 @@ function BrowserGlue() {
|
|||
|
||||
BrowserGlue.prototype = {
|
||||
_saveSession: false,
|
||||
_isIdleObserver: false,
|
||||
_isPlacesInitObserver: false,
|
||||
_isPlacesLockedObserver: false,
|
||||
_isPlacesShutdownObserver: false,
|
||||
|
@ -202,16 +205,7 @@ BrowserGlue.prototype = {
|
|||
this._onQuitRequest(subject, data);
|
||||
break;
|
||||
case "quit-application-granted":
|
||||
// This pref must be set here because SessionStore will use its value
|
||||
// on quit-application.
|
||||
this._setPrefToSaveSession();
|
||||
try {
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
|
||||
getService(Ci.nsIAppStartup);
|
||||
appStartup.trackStartupCrashEnd();
|
||||
} catch (e) {
|
||||
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
|
||||
}
|
||||
this._onQuitApplicationGranted();
|
||||
break;
|
||||
#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
|
||||
case "browser-lastwindow-close-requested":
|
||||
|
@ -262,8 +256,7 @@ BrowserGlue.prototype = {
|
|||
this._onPlacesShutdown();
|
||||
break;
|
||||
case "idle":
|
||||
if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
|
||||
this._backupBookmarks();
|
||||
this._backupBookmarks();
|
||||
break;
|
||||
case "distribution-customization-complete":
|
||||
Services.obs.removeObserver(this, "distribution-customization-complete");
|
||||
|
@ -304,7 +297,10 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
break;
|
||||
case "profile-before-change":
|
||||
this._onProfileShutdown();
|
||||
// Any component depending on Places should be finalized in
|
||||
// _onPlacesShutdown. Any component that doesn't need to act after
|
||||
// the UI has gone should be finalized in _onQuitApplicationGranted.
|
||||
this._dispose();
|
||||
break;
|
||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||
case "keyword-search":
|
||||
|
@ -422,8 +418,10 @@ BrowserGlue.prototype = {
|
|||
os.removeObserver(this, "weave:engine:clients:display-uri");
|
||||
#endif
|
||||
os.removeObserver(this, "session-save");
|
||||
if (this._isIdleObserver)
|
||||
this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
|
||||
if (this._bookmarksBackupIdleTime) {
|
||||
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
|
||||
delete this._bookmarksBackupIdleTime;
|
||||
}
|
||||
if (this._isPlacesInitObserver)
|
||||
os.removeObserver(this, "places-init-complete");
|
||||
if (this._isPlacesLockedObserver)
|
||||
|
@ -634,16 +632,24 @@ BrowserGlue.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Profile shutdown handler (contains profile cleanup routines).
|
||||
* All components depending on Places should be shut down in
|
||||
* _onPlacesShutdown() and not here.
|
||||
* Application shutdown handler.
|
||||
*/
|
||||
_onProfileShutdown: function BG__onProfileShutdown() {
|
||||
_onQuitApplicationGranted: function () {
|
||||
// This pref must be set here because SessionStore will use its value
|
||||
// on quit-application.
|
||||
this._setPrefToSaveSession();
|
||||
try {
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup);
|
||||
appStartup.trackStartupCrashEnd();
|
||||
} catch (e) {
|
||||
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
|
||||
}
|
||||
|
||||
BrowserNewTabPreloader.uninit();
|
||||
webappsUI.uninit();
|
||||
SignInToWebsiteUX.uninit();
|
||||
webrtcUI.uninit();
|
||||
this._dispose();
|
||||
},
|
||||
|
||||
// All initial windows have opened.
|
||||
|
@ -1060,14 +1066,18 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
} catch(ex) {}
|
||||
|
||||
// This may be reused later, check for "=== undefined" to see if it has
|
||||
// been populated already.
|
||||
let lastBackupFile;
|
||||
|
||||
// If the user did not require to restore default bookmarks, or import
|
||||
// from bookmarks.html, we will try to restore from JSON
|
||||
if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
|
||||
// get latest JSON backup
|
||||
var bookmarksBackupFile = yield PlacesBackups.getMostRecent("json");
|
||||
if (bookmarksBackupFile) {
|
||||
lastBackupFile = yield PlacesBackups.getMostRecentBackup("json");
|
||||
if (lastBackupFile) {
|
||||
// restore from JSON backup
|
||||
yield BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true);
|
||||
yield BookmarkJSONUtils.importFromFile(lastBackupFile, true);
|
||||
importBookmarks = false;
|
||||
}
|
||||
else {
|
||||
|
@ -1162,10 +1172,39 @@ BrowserGlue.prototype = {
|
|||
}
|
||||
|
||||
// Initialize bookmark archiving on idle.
|
||||
// Once a day, either on idle or shutdown, bookmarks are backed up.
|
||||
if (!this._isIdleObserver) {
|
||||
this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
|
||||
this._isIdleObserver = true;
|
||||
if (!this._bookmarksBackupIdleTime) {
|
||||
this._bookmarksBackupIdleTime = BOOKMARKS_BACKUP_IDLE_TIME_SEC;
|
||||
|
||||
// If there is no backup, or the last bookmarks backup is too old, use
|
||||
// a more aggressive idle observer.
|
||||
if (lastBackupFile === undefined)
|
||||
lastBackupFile = yield PlacesBackups.getMostRecentBackup();
|
||||
if (!lastBackupFile) {
|
||||
this._bookmarksBackupIdleTime /= 2;
|
||||
}
|
||||
else {
|
||||
let lastBackupTime = PlacesBackups.getDateForFile(lastBackupFile);
|
||||
let profileLastUse = Services.appinfo.replacedLockTime || Date.now();
|
||||
|
||||
// If there is a backup after the last profile usage date it's fine,
|
||||
// regardless its age. Otherwise check how old is the last
|
||||
// available backup compared to that session.
|
||||
if (profileLastUse > lastBackupTime) {
|
||||
let backupAge = Math.round((profileLastUse - lastBackupTime) / 86400000);
|
||||
// Report the age of the last available backup.
|
||||
try {
|
||||
Services.telemetry
|
||||
.getHistogramById("PLACES_BACKUPS_DAYSFROMLAST")
|
||||
.add(backupAge);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to report telemetry.");
|
||||
}
|
||||
|
||||
if (backupAge > BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS)
|
||||
this._bookmarksBackupIdleTime /= 2;
|
||||
}
|
||||
}
|
||||
this._idleService.addIdleObserver(this, this._bookmarksBackupIdleTime);
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "places-browser-init-complete", "");
|
||||
|
@ -1174,63 +1213,34 @@ BrowserGlue.prototype = {
|
|||
|
||||
/**
|
||||
* Places shut-down tasks
|
||||
* - back up bookmarks if needed.
|
||||
* - export bookmarks as HTML, if so configured.
|
||||
* - finalize components depending on Places.
|
||||
* - export bookmarks as HTML, if so configured.
|
||||
*/
|
||||
_onPlacesShutdown: function BG__onPlacesShutdown() {
|
||||
this._sanitizer.onShutdown();
|
||||
PageThumbs.uninit();
|
||||
|
||||
if (this._isIdleObserver) {
|
||||
this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
|
||||
this._isIdleObserver = false;
|
||||
if (this._bookmarksBackupIdleTime) {
|
||||
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
|
||||
delete this._bookmarksBackupIdleTime;
|
||||
}
|
||||
|
||||
let waitingForBackupToComplete = true;
|
||||
this._backupBookmarks().then(
|
||||
function onSuccess() {
|
||||
waitingForBackupToComplete = false;
|
||||
},
|
||||
function onFailure() {
|
||||
Cu.reportError("Unable to backup bookmarks.");
|
||||
waitingForBackupToComplete = false;
|
||||
// Support legacy bookmarks.html format for apps that depend on that format.
|
||||
try {
|
||||
if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
|
||||
// places-shutdown happens at profile-change-teardown, so here we
|
||||
// can safely add a profile-before-change blocker.
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
"Places: bookmarks.html",
|
||||
() => BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks", Ci.nsIFile))
|
||||
.then(null, Cu.reportError)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Backup bookmarks to bookmarks.html to support apps that depend
|
||||
// on the legacy format.
|
||||
let waitingForHTMLExportToComplete = false;
|
||||
// If this fails to get the preference value, we don't export.
|
||||
if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
|
||||
// Exceptionally, since this is a non-default setting and HTML format is
|
||||
// discouraged in favor of the JSON backups, we spin the event loop on
|
||||
// shutdown, to wait for the export to finish. We cannot safely spin
|
||||
// the event loop on shutdown until we include a watchdog to prevent
|
||||
// potential hangs (bug 518683). The asynchronous shutdown operations
|
||||
// will then be handled by a shutdown service (bug 435058).
|
||||
waitingForHTMLExportToComplete = true;
|
||||
BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks", Ci.nsIFile)).then(
|
||||
function onSuccess() {
|
||||
waitingForHTMLExportToComplete = false;
|
||||
},
|
||||
function onFailure() {
|
||||
Cu.reportError("Unable to auto export html.");
|
||||
waitingForHTMLExportToComplete = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// The events loop should spin at least once because waitingForBackupToComplete
|
||||
// is true before checking whether backup should be made.
|
||||
let thread = Services.tm.currentThread;
|
||||
while (waitingForBackupToComplete || waitingForHTMLExportToComplete) {
|
||||
thread.processNextEvent(true);
|
||||
}
|
||||
} catch (ex) {} // Do not export.
|
||||
},
|
||||
|
||||
/**
|
||||
* Backup bookmarks.
|
||||
* If a backup for today doesn't exist, this creates one.
|
||||
*/
|
||||
_backupBookmarks: function BG__backupBookmarks() {
|
||||
return Task.spawn(function() {
|
||||
|
@ -1238,14 +1248,9 @@ BrowserGlue.prototype = {
|
|||
// Should backup bookmarks if there are no backups or the maximum
|
||||
// interval between backups elapsed.
|
||||
if (!lastBackupFile ||
|
||||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
|
||||
let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
|
||||
try {
|
||||
maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
|
||||
}
|
||||
catch(ex) { /* Use default. */ }
|
||||
|
||||
yield PlacesBackups.create(maxBackups); // Don't force creation.
|
||||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS * 86400000) {
|
||||
let maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
|
||||
yield PlacesBackups.create(maxBackups);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -540,7 +540,8 @@ var PlacesOrganizer = {
|
|||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
let fpCallback = function fpCallback_done(aResult) {
|
||||
if (aResult != Ci.nsIFilePicker.returnCancel) {
|
||||
PlacesBackups.saveBookmarksToJSONFile(fp.file);
|
||||
// There is no OS.File version of the filepicker yet (Bug 937812).
|
||||
PlacesBackups.saveBookmarksToJSONFile(fp.file.path);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,91 +4,78 @@
|
|||
* 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/. */
|
||||
|
||||
// Get bookmarks service
|
||||
try {
|
||||
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
} catch(ex) {
|
||||
do_throw("Could not get Bookmarks service\n");
|
||||
}
|
||||
|
||||
// Get annotation service
|
||||
try {
|
||||
var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].
|
||||
getService(Ci.nsIAnnotationService);
|
||||
} catch(ex) {
|
||||
do_throw("Could not get Annotation service\n");
|
||||
}
|
||||
|
||||
// Get browser glue
|
||||
try {
|
||||
var gluesvc = Cc["@mozilla.org/browser/browserglue;1"].
|
||||
getService(Ci.nsIBrowserGlue).
|
||||
QueryInterface(Ci.nsIObserver);
|
||||
// Avoid default bookmarks import.
|
||||
gluesvc.observe(null, "initial-migration-will-import-default-bookmarks", "");
|
||||
// gluesvc.observe(null, "initial-migration-did-import-default-bookmarks", "");
|
||||
} catch(ex) {
|
||||
do_throw("Could not get BrowserGlue service\n");
|
||||
}
|
||||
|
||||
// Get pref service
|
||||
try {
|
||||
var pref = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
} catch(ex) {
|
||||
do_throw("Could not get Preferences service\n");
|
||||
}
|
||||
|
||||
const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
|
||||
const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
|
||||
|
||||
// main
|
||||
let gluesvc = Cc["@mozilla.org/browser/browserglue;1"].
|
||||
getService(Ci.nsIBrowserGlue).
|
||||
QueryInterface(Ci.nsIObserver);
|
||||
// Avoid default bookmarks import.
|
||||
gluesvc.observe(null, "initial-migration-will-import-default-bookmarks", "");
|
||||
|
||||
function run_test() {
|
||||
// TEST 1: smart bookmarks disabled
|
||||
pref.setIntPref("browser.places.smartBookmarksVersion", -1);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
var smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, 0);
|
||||
// check that pref has not been bumped up
|
||||
do_check_eq(pref.getIntPref("browser.places.smartBookmarksVersion"), -1);
|
||||
|
||||
// TEST 2: create smart bookmarks
|
||||
pref.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_neq(smartBookmarkItemIds.length, 0);
|
||||
// check that pref has been bumped up
|
||||
do_check_true(pref.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
|
||||
var smartBookmarksCount = smartBookmarkItemIds.length;
|
||||
|
||||
// TEST 3: smart bookmarks restore
|
||||
// remove one smart bookmark and restore
|
||||
bmsvc.removeItem(smartBookmarkItemIds[0]);
|
||||
pref.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount);
|
||||
// check that pref has been bumped up
|
||||
do_check_true(pref.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
|
||||
// TEST 4: move a smart bookmark, change its title, then restore
|
||||
// smart bookmark should be restored in place
|
||||
var parent = bmsvc.getFolderIdForItem(smartBookmarkItemIds[0]);
|
||||
var oldTitle = bmsvc.getItemTitle(smartBookmarkItemIds[0]);
|
||||
// create a subfolder and move inside it
|
||||
var newParent = bmsvc.createFolder(parent, "test", bmsvc.DEFAULT_INDEX);
|
||||
bmsvc.moveItem(smartBookmarkItemIds[0], newParent, bmsvc.DEFAULT_INDEX);
|
||||
// change title
|
||||
bmsvc.setItemTitle(smartBookmarkItemIds[0], "new title");
|
||||
// restore
|
||||
pref.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount);
|
||||
do_check_eq(bmsvc.getFolderIdForItem(smartBookmarkItemIds[0]), newParent);
|
||||
do_check_eq(bmsvc.getItemTitle(smartBookmarkItemIds[0]), oldTitle);
|
||||
// check that pref has been bumped up
|
||||
do_check_true(pref.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function smart_bookmarks_disabled() {
|
||||
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
let smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, 0);
|
||||
do_log_info("check that pref has not been bumped up");
|
||||
do_check_eq(Services.prefs.getIntPref("browser.places.smartBookmarksVersion"), -1);
|
||||
});
|
||||
|
||||
add_task(function create_smart_bookmarks() {
|
||||
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
let smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_neq(smartBookmarkItemIds.length, 0);
|
||||
do_log_info("check that pref has been bumped up");
|
||||
do_check_true(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
});
|
||||
|
||||
add_task(function remove_smart_bookmark_and_restore() {
|
||||
let smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
let smartBookmarksCount = smartBookmarkItemIds.length;
|
||||
do_log_info("remove one smart bookmark and restore");
|
||||
PlacesUtils.bookmarks.removeItem(smartBookmarkItemIds[0]);
|
||||
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
let smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount);
|
||||
do_log_info("check that pref has been bumped up");
|
||||
do_check_true(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
});
|
||||
|
||||
add_task(function move_smart_bookmark_rename_and_restore() {
|
||||
let smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
let smartBookmarksCount = smartBookmarkItemIds.length;
|
||||
do_log_info("smart bookmark should be restored in place");
|
||||
let parent = PlacesUtils.bookmarks.getFolderIdForItem(smartBookmarkItemIds[0]);
|
||||
let oldTitle = PlacesUtils.bookmarks.getItemTitle(smartBookmarkItemIds[0]);
|
||||
// create a subfolder and move inside it
|
||||
let newParent =
|
||||
PlacesUtils.bookmarks.createFolder(parent, "test",
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
PlacesUtils.bookmarks.moveItem(smartBookmarkItemIds[0], newParent,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
// change title
|
||||
PlacesUtils.bookmarks.setItemTitle(smartBookmarkItemIds[0], "new title");
|
||||
// restore
|
||||
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
|
||||
gluesvc.ensurePlacesDefaultQueriesInitialized();
|
||||
smartBookmarkItemIds =
|
||||
PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO);
|
||||
do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount);
|
||||
do_check_eq(PlacesUtils.bookmarks.getFolderIdForItem(smartBookmarkItemIds[0]), newParent);
|
||||
do_check_eq(PlacesUtils.bookmarks.getItemTitle(smartBookmarkItemIds[0]), oldTitle);
|
||||
do_log_info("check that pref has been bumped up");
|
||||
do_check_true(Services.prefs.getIntPref("browser.places.smartBookmarksVersion") > 0);
|
||||
});
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Tests that nsBrowserGlue is correctly exporting based on preferences values,
|
||||
* and creating bookmarks backup if one does not exist for today.
|
||||
*/
|
||||
|
||||
// Initialize nsBrowserGlue after Places.
|
||||
let bg = Cc["@mozilla.org/browser/browserglue;1"].
|
||||
getService(Ci.nsIBrowserGlue);
|
||||
|
||||
// Initialize Places through Bookmarks Service.
|
||||
let bs = PlacesUtils.bookmarks;
|
||||
|
||||
// Get other services.
|
||||
let ps = Services.prefs;
|
||||
let os = Services.obs;
|
||||
|
||||
const PREF_AUTO_EXPORT_HTML = "browser.bookmarks.autoExportHTML";
|
||||
|
||||
let tests = [];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
description: "Export to bookmarks.html if autoExportHTML is true.",
|
||||
exec: function() {
|
||||
remove_all_JSON_backups();
|
||||
|
||||
// Sanity check: we should have bookmarks on the toolbar.
|
||||
do_check_true(bs.getIdForItemAt(bs.toolbarFolder, 0) > 0);
|
||||
|
||||
// Set preferences.
|
||||
ps.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
|
||||
|
||||
// Force nsBrowserGlue::_shutdownPlaces().
|
||||
bg.QueryInterface(Ci.nsIObserver).observe(null,
|
||||
PlacesUtils.TOPIC_SHUTDOWN,
|
||||
null);
|
||||
|
||||
// Check bookmarks.html has been created.
|
||||
check_bookmarks_html();
|
||||
// Check JSON backup has been created.
|
||||
check_JSON_backup(true);
|
||||
|
||||
// Check preferences have not been reverted.
|
||||
do_check_true(ps.getBoolPref(PREF_AUTO_EXPORT_HTML));
|
||||
// Reset preferences.
|
||||
ps.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
|
||||
|
||||
next_test();
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
description: "Export to bookmarks.html if autoExportHTML is true and a bookmarks.html exists.",
|
||||
exec: function() {
|
||||
// Sanity check: we should have bookmarks on the toolbar.
|
||||
do_check_true(bs.getIdForItemAt(bs.toolbarFolder, 0) > 0);
|
||||
|
||||
// Set preferences.
|
||||
ps.setBoolPref(PREF_AUTO_EXPORT_HTML, true);
|
||||
|
||||
// Create a bookmarks.html in the profile.
|
||||
let profileBookmarksHTMLFile = create_bookmarks_html("bookmarks.glue.html");
|
||||
|
||||
// set the file's lastModifiedTime to one minute ago and get its size.
|
||||
let lastMod = Date.now() - 60*1000;
|
||||
profileBookmarksHTMLFile.lastModifiedTime = lastMod;
|
||||
|
||||
let fileSize = profileBookmarksHTMLFile.fileSize;
|
||||
|
||||
// Force nsBrowserGlue::_shutdownPlaces().
|
||||
bg.QueryInterface(Ci.nsIObserver).observe(null,
|
||||
PlacesUtils.TOPIC_SHUTDOWN,
|
||||
null);
|
||||
|
||||
// Check a new bookmarks.html has been created.
|
||||
let profileBookmarksHTMLFile = check_bookmarks_html();
|
||||
do_check_true(profileBookmarksHTMLFile.lastModifiedTime > lastMod);
|
||||
do_check_neq(profileBookmarksHTMLFile.fileSize, fileSize);
|
||||
|
||||
// Check preferences have not been reverted.
|
||||
do_check_true(ps.getBoolPref(PREF_AUTO_EXPORT_HTML));
|
||||
// Reset preferences.
|
||||
ps.setBoolPref(PREF_AUTO_EXPORT_HTML, false);
|
||||
|
||||
next_test();
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
description: "Backup to JSON should be a no-op if a backup for today already exists.",
|
||||
exec: function() {
|
||||
// Sanity check: we should have bookmarks on the toolbar.
|
||||
do_check_true(bs.getIdForItemAt(bs.toolbarFolder, 0) > 0);
|
||||
|
||||
// Create a JSON backup in the profile.
|
||||
let profileBookmarksJSONFile = create_JSON_backup("bookmarks.glue.json");
|
||||
// Get file lastModified and size.
|
||||
let lastMod = profileBookmarksJSONFile.lastModifiedTime;
|
||||
let fileSize = profileBookmarksJSONFile.fileSize;
|
||||
|
||||
// Force nsBrowserGlue::_shutdownPlaces().
|
||||
bg.QueryInterface(Ci.nsIObserver).observe(null,
|
||||
PlacesUtils.TOPIC_SHUTDOWN,
|
||||
null);
|
||||
|
||||
// Check a new JSON backup has not been created.
|
||||
do_check_true(profileBookmarksJSONFile.exists());
|
||||
do_check_eq(profileBookmarksJSONFile.lastModifiedTime, lastMod);
|
||||
do_check_eq(profileBookmarksJSONFile.fileSize, fileSize);
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
var testIndex = 0;
|
||||
function next_test() {
|
||||
// Remove bookmarks.html from profile.
|
||||
remove_bookmarks_html();
|
||||
|
||||
// Execute next test.
|
||||
let test = tests.shift();
|
||||
dump("\nTEST " + (++testIndex) + ": " + test.description);
|
||||
test.exec();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
// Clean up bookmarks.
|
||||
remove_all_bookmarks();
|
||||
|
||||
// Create some bookmarks.
|
||||
bs.insertBookmark(bs.bookmarksMenuFolder, uri("http://mozilla.org/"),
|
||||
bs.DEFAULT_INDEX, "bookmark-on-menu");
|
||||
bs.insertBookmark(bs.toolbarFolder, uri("http://mozilla.org/"),
|
||||
bs.DEFAULT_INDEX, "bookmark-on-toolbar");
|
||||
|
||||
// Kick-off tests.
|
||||
next_test();
|
||||
}
|
|
@ -19,8 +19,8 @@ const TOPIC_CONNECTION_CLOSED = "places-connection-closed";
|
|||
|
||||
let EXPECTED_NOTIFICATIONS = [
|
||||
"places-shutdown"
|
||||
, "places-expiration-finished"
|
||||
, "places-will-close-connection"
|
||||
, "places-expiration-finished"
|
||||
, "places-connection-closed"
|
||||
];
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ support-files =
|
|||
[test_browserGlue_migrate.js]
|
||||
[test_browserGlue_prefs.js]
|
||||
[test_browserGlue_restore.js]
|
||||
[test_browserGlue_shutdown.js]
|
||||
[test_browserGlue_smartBookmarks.js]
|
||||
[test_clearHistory_shutdown.js]
|
||||
[test_leftpane_corruption_handling.js]
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
malformedURI=The URL is not valid and cannot be loaded.
|
||||
fileNotFound=Firefox can't find the file at %S.
|
||||
dnsNotFound=Firefox can't find the server at %S.
|
||||
protocolNotFound=Firefox doesn't know how to open this address, because the protocol (%S) isn't associated with any program.
|
||||
unknownProtocolFound=Firefox doesn't know how to open this address, because one of the following protocols (%S) isn't associated with any program or is not allowed in this context.
|
||||
connectionFailure=Firefox can't establish a connection to the server at %S.
|
||||
netInterrupt=The connection to %S was interrupted while the page was loading.
|
||||
netTimeout=The server at %S is taking too long to respond.
|
||||
|
|
|
@ -86,8 +86,8 @@
|
|||
<!ENTITY netTimeout.title "The connection has timed out">
|
||||
<!ENTITY netTimeout.longDesc "&sharedLongDesc;">
|
||||
|
||||
<!ENTITY protocolNotFound.title "The address wasn't understood">
|
||||
<!ENTITY protocolNotFound.longDesc "
|
||||
<!ENTITY unknownProtocolFound.title "The address wasn't understood">
|
||||
<!ENTITY unknownProtocolFound.longDesc "
|
||||
<ul>
|
||||
<li>You might need to install other software to open this address.</li>
|
||||
</ul>
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -275,7 +275,7 @@
|
|||
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
||||
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
||||
<h1 id="et_malformedURI">&malformedURI.title;</h1>
|
||||
<h1 id="et_protocolNotFound">&protocolNotFound.title;</h1>
|
||||
<h1 id="et_unknownProtocolFound">&unknownProtocolFound.title;</h1>
|
||||
<h1 id="et_connectionFailure">&connectionFailure.title;</h1>
|
||||
<h1 id="et_netTimeout">&netTimeout.title;</h1>
|
||||
<h1 id="et_redirectLoop">&redirectLoop.title;</h1>
|
||||
|
@ -300,7 +300,7 @@
|
|||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
|
||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||
<div id="ed_malformedURI">&malformedURI.longDesc;</div>
|
||||
<div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
|
||||
<div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
|
||||
<div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
|
||||
<div id="ed_netTimeout">&netTimeout.longDesc;</div>
|
||||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
<tt> aa_block: /* innermost frame denies a */</tt><br/>
|
||||
<iframe id='aa_block'></iframe><br/>
|
||||
|
||||
<tt> aa2_block: /* innermost frame (view-source: URL) denies a */</tt><br/>
|
||||
<iframe id='aa2_block'></iframe><br/>
|
||||
|
||||
<tt> ab_allow: /* innermost frame allows a */</tt><br/>
|
||||
<iframe id='ab_allow'></iframe><br/>
|
||||
|
||||
|
|
|
@ -22,10 +22,6 @@ function setupFrames() {
|
|||
elt.src = base.a + "?testid=aa_block&internalframe=aa_b&csp=" +
|
||||
escape("allow 'none'; frame-ancestors 'none'; script-src 'self'");
|
||||
|
||||
elt = $('aa2_block');
|
||||
elt.src = "view-source:" + base.a + "?testid=aa2_block&internalframe=aa_b&csp=" +
|
||||
escape("allow 'none'; frame-ancestors 'none'; script-src 'self'");
|
||||
|
||||
elt = $('ab_allow');
|
||||
elt.src = base.b + "?testid=ab_allow&internalframe=ab_a&csp=" +
|
||||
escape("allow 'none'; frame-ancestors " + host.a + "; script-src 'self'");
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
<tt> aa_block: /* innermost frame denies a */</tt><br/>
|
||||
<iframe id='aa_block_spec_compliant'></iframe><br/>
|
||||
|
||||
<tt> aa2_block: /* innermost frame (view-source: URL) denies a */</tt><br/>
|
||||
<iframe id='aa2_block_spec_compliant'></iframe><br/>
|
||||
|
||||
<tt> ab_allow: /* innermost frame allows a */</tt><br/>
|
||||
<iframe id='ab_allow_spec_compliant'></iframe><br/>
|
||||
|
||||
|
|
|
@ -22,10 +22,6 @@ function setupFrames() {
|
|||
elt.src = base.a + "?testid=aa_block_spec_compliant&internalframe=aa_b&csp=" +
|
||||
escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'");
|
||||
|
||||
elt = $('aa2_block_spec_compliant');
|
||||
elt.src = "view-source:" + base.a + "?testid=aa2_block_spec_compliant&internalframe=aa_b&csp=" +
|
||||
escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'");
|
||||
|
||||
elt = $('ab_allow_spec_compliant');
|
||||
elt.src = base.b + "?testid=ab_allow_spec_compliant&internalframe=ab_a&csp=" +
|
||||
escape("default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'");
|
||||
|
|
|
@ -20,7 +20,6 @@ var path = "/tests/content/base/test/csp/";
|
|||
var framesThatShouldLoad = {
|
||||
aa_allow: -1, /* innermost frame allows a */
|
||||
//aa_block: -1, /* innermost frame denies a */
|
||||
//aa2_block: -1, /* innermost frame denies a */
|
||||
ab_allow: -1, /* innermost frame allows a */
|
||||
//ab_block: -1, /* innermost frame denies a */
|
||||
aba_allow: -1, /* innermost frame allows b,a */
|
||||
|
@ -31,7 +30,6 @@ var framesThatShouldLoad = {
|
|||
//abb2_block: -1, /* innermost frame denies a */
|
||||
aa_allow_spec_compliant: -1, /* innermost frame allows a *
|
||||
//aa_block_spec_compliant: -1, /* innermost frame denies a */
|
||||
//aa2_block_spec_compliant: -1, /* innermost frame denies a */
|
||||
ab_allow_spec_compliant: -1, /* innermost frame allows a */
|
||||
//ab_block_spec_compliant: -1, /* innermost frame denies a */
|
||||
aba_allow_spec_compliant: -1, /* innermost frame allows b,a */
|
||||
|
@ -42,7 +40,7 @@ var framesThatShouldLoad = {
|
|||
//abb2_block_spec_compliant: -1, /* innermost frame denies a */
|
||||
};
|
||||
|
||||
var expectedViolationsLeft = 14;
|
||||
var expectedViolationsLeft = 12;
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
|
|
|
@ -4386,12 +4386,25 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||
// Turn the error code into a human readable error message.
|
||||
if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
// extract the scheme
|
||||
|
||||
// Extract the schemes into a comma delimited list.
|
||||
nsAutoCString scheme;
|
||||
aURI->GetScheme(scheme);
|
||||
CopyASCIItoUTF16(scheme, formatStrs[0]);
|
||||
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
|
||||
while (nestedURI) {
|
||||
nsCOMPtr<nsIURI> tempURI;
|
||||
nsresult rv2;
|
||||
rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
|
||||
if (NS_SUCCEEDED(rv2) && tempURI) {
|
||||
tempURI->GetScheme(scheme);
|
||||
formatStrs[0].Append(NS_LITERAL_STRING(", "));
|
||||
AppendASCIItoUTF16(scheme, formatStrs[0]);
|
||||
}
|
||||
nestedURI = do_QueryInterface(tempURI);
|
||||
}
|
||||
formatStrCount = 1;
|
||||
error.AssignLiteral("protocolNotFound");
|
||||
error.AssignLiteral("unknownProtocolFound");
|
||||
}
|
||||
else if (NS_ERROR_FILE_NOT_FOUND == aError) {
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
@ -9682,6 +9695,25 @@ nsDocShell::DoURILoad(nsIURI * aURI,
|
|||
channelPolicy->SetLoadType(nsIContentPolicy::TYPE_SUBDOCUMENT);
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow view-source scheme in top-level docshells. view-source is
|
||||
// the only scheme to which this applies at the moment due to potential
|
||||
// timing attacks to read data from cross-origin iframes. If this widens
|
||||
// we should add a protocol flag for whether the scheme is allowed in
|
||||
// frames and use something like nsNetUtil::NS_URIChainHasFlags.
|
||||
nsCOMPtr<nsIURI> tempURI = aURI;
|
||||
nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
|
||||
while (nestedURI) {
|
||||
// view-source should always be an nsINestedURI, loop and check the
|
||||
// scheme on this and all inner URIs that are also nested URIs.
|
||||
bool isViewSource = false;
|
||||
rv = tempURI->SchemeIs("view-source", &isViewSource);
|
||||
if (NS_FAILED(rv) || isViewSource) {
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
nestedURI->GetInnerURI(getter_AddRefs(tempURI));
|
||||
nestedURI = do_QueryInterface(tempURI);
|
||||
}
|
||||
}
|
||||
|
||||
// open a channel for the url
|
||||
|
|
|
@ -274,7 +274,7 @@
|
|||
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
||||
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
||||
<h1 id="et_malformedURI">&malformedURI.title;</h1>
|
||||
<h1 id="et_protocolNotFound">&protocolNotFound.title;</h1>
|
||||
<h1 id="et_unknownProtocolFound">&unknownProtocolFound.title;</h1>
|
||||
<h1 id="et_connectionFailure">&connectionFailure.title;</h1>
|
||||
<h1 id="et_netTimeout">&netTimeout.title;</h1>
|
||||
<h1 id="et_redirectLoop">&redirectLoop.title;</h1>
|
||||
|
@ -300,7 +300,7 @@
|
|||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc;</div>
|
||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||
<div id="ed_malformedURI">&malformedURI.longDesc;</div>
|
||||
<div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
|
||||
<div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
|
||||
<div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
|
||||
<div id="ed_netTimeout">&netTimeout.longDesc;</div>
|
||||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
|
|
|
@ -42,6 +42,7 @@ support-files =
|
|||
bug909218.js
|
||||
bug92598_window.xul
|
||||
docshell_helpers.js
|
||||
file_viewsource_forbidden_in_iframe.html
|
||||
generic.html
|
||||
mozFrameType_window.xul
|
||||
|
||||
|
@ -78,3 +79,4 @@ support-files =
|
|||
[test_mozFrameType.xul]
|
||||
[test_principalInherit.xul]
|
||||
[test_private_hidden_window.html]
|
||||
[test_viewsource_forbidden_in_iframe.xul]
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test ifranes for view-source forbidden in iframe tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="testIframe"></iframe>
|
||||
<iframe id="refIframe"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,180 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin/"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=624883
|
||||
-->
|
||||
<window title="Mozilla Bug 624883"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=624883"
|
||||
target="_blank">Mozilla Bug 624883</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<iframe type="content" onload="startTest()" src="file_viewsource_forbidden_in_iframe.html"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// We create a promise that will resolve with the error message
|
||||
// on a network error page load and reject on any other load.
|
||||
function createNetworkErrorMessagePromise(frame) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
// Error pages do not fire "load" events, so use a progressListener.
|
||||
var originalDocumentURI = frame.contentDocument.documentURI;
|
||||
var progressListener = {
|
||||
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
// Make sure nothing other than an error page is loaded.
|
||||
if (!(aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE)) {
|
||||
reject("location change was not to an error page");
|
||||
}
|
||||
},
|
||||
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
// Wait until the documentURI changes (from about:blank) this should
|
||||
// be the error page URI.
|
||||
var documentURI = frame.contentDocument.documentURI;
|
||||
if (documentURI == originalDocumentURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
aWebProgress.removeProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
var matchArray = /about:neterror\?.*&d=([^&]*)/.exec(documentURI);
|
||||
if (!matchArray) {
|
||||
reject("no network error message found in URI")
|
||||
return;
|
||||
}
|
||||
|
||||
var errorMsg = matchArray[1];
|
||||
resolve(decodeURIComponent(errorMsg));
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
frame.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress)
|
||||
.addProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION |
|
||||
Ci.nsIWebProgress.NOTIFY_STATE_REQUEST);
|
||||
});
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// Get a reference message that we know will be an unknown protocol message,
|
||||
// so we can use it for comparisons in the test cases.
|
||||
var refIframe = window[0].document.getElementById("refIframe");
|
||||
var refErrorPromise = createNetworkErrorMessagePromise(refIframe);
|
||||
|
||||
refErrorPromise.then(
|
||||
function(msg) {
|
||||
window.refErrorMsg = msg;
|
||||
var testIframe = window[0].document.getElementById("testIframe");
|
||||
|
||||
// Run test cases on load of "about:blank", so that the URI always changes
|
||||
// and we can detect this in our Promise.
|
||||
testIframe.onload = runNextTestCase;
|
||||
testIframe.src = "about:blank";
|
||||
},
|
||||
function(reason) {
|
||||
ok(false, "Could not get reference error message", reason);
|
||||
SimpleTest.finish();
|
||||
})
|
||||
.catch(function(e) {
|
||||
ok(false, "Unexpected exception thrown getting reference error message", exception);
|
||||
});
|
||||
|
||||
refIframe.src = "wibble://example.com";
|
||||
}
|
||||
|
||||
function runTestCase(testCase) {
|
||||
var testIframe = window[0].document.getElementById("testIframe");
|
||||
var expectedErrorMsg = window.refErrorMsg.replace("wibble", testCase.expectedProtocolList);
|
||||
|
||||
var testErrorPromise = createNetworkErrorMessagePromise(testIframe);
|
||||
testErrorPromise.then(
|
||||
function(actualErrorMsg) {
|
||||
is(actualErrorMsg, expectedErrorMsg, testCase.desc);
|
||||
testIframe.src = "about:blank";
|
||||
},
|
||||
function(reason) {
|
||||
ok(false, testCase.desc, reason);
|
||||
testIframe.src = "about:blank";
|
||||
})
|
||||
.catch(function(e) {
|
||||
ok(false, testCase.desc + " - unexpected exception thrown", exception);
|
||||
});
|
||||
|
||||
testIframe.src = testCase.protocols + "://example.com/!/";
|
||||
}
|
||||
|
||||
var testCaseIndex = -1;
|
||||
testCases = [
|
||||
{
|
||||
desc: "Test 1: view-source should not be allowed in an iframe",
|
||||
protocols: "view-source:http",
|
||||
expectedProtocolList: "view-source, http"
|
||||
},
|
||||
{
|
||||
desc: "Test 2: feed:view-source should not be allowed in an iframe",
|
||||
protocols: "feed:view-source:http",
|
||||
expectedProtocolList: "feed, view-source, http"
|
||||
},
|
||||
{
|
||||
desc: "Test 3: jar:view-source should not be allowed in an iframe",
|
||||
protocols: "jar:view-source:http",
|
||||
expectedProtocolList: "jar, view-source, http"
|
||||
},
|
||||
{
|
||||
desc: "Test 4: pcast:view-source should not be allowed in an iframe",
|
||||
protocols: "pcast:view-source:http",
|
||||
expectedProtocolList: "pcast, view-source, http"
|
||||
},
|
||||
{
|
||||
desc: "Test 5: pcast:feed:view-source should not be allowed in an iframe",
|
||||
protocols: "pcast:feed:view-source:http",
|
||||
expectedProtocolList: "pcast, feed, view-source, http"
|
||||
},
|
||||
{
|
||||
desc: "Test 6: if invalid protocol first should report before view-source",
|
||||
protocols: "wibble:view-source:http",
|
||||
// Nothing after the invalid protocol gets set as a proper nested URI,
|
||||
// so the list stops there.
|
||||
expectedProtocolList: "wibble"
|
||||
},
|
||||
{
|
||||
desc: "Test 7: if view-source first should report before invalid protocol",
|
||||
protocols: "view-source:wibble:http",
|
||||
expectedProtocolList: "view-source, wibble"
|
||||
}
|
||||
];
|
||||
|
||||
function runNextTestCase() {
|
||||
++testCaseIndex;
|
||||
if (testCaseIndex == testCases.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
runTestCase(testCases[testCaseIndex]);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1926,11 +1926,6 @@ Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal)
|
|||
{
|
||||
JS::Rooted<JSObject*> global(cx, aGlobal);
|
||||
|
||||
// DataStore is enabled by default for chrome code.
|
||||
if (nsContentUtils::IsCallerChrome()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// First of all, the general pref has to be turned on.
|
||||
bool enabled = false;
|
||||
Preferences::GetBool("dom.datastore.enabled", &enabled);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
malformedURI=The URL is not valid and cannot be loaded.
|
||||
fileNotFound=The file %S cannot be found. Please check the location and try again.
|
||||
dnsNotFound=%S could not be found. Please check the name and try again.
|
||||
protocolNotFound=%S is not a registered protocol.
|
||||
unknownProtocolFound=One of the following %S is not a registered protocol or is not allowed in this context.
|
||||
connectionFailure=The connection was refused when attempting to contact %S.
|
||||
netInterrupt=The connection to %S has terminated unexpectedly. Some data may have been transferred.
|
||||
netTimeout=The operation timed out when attempting to contact %S.
|
||||
|
|
|
@ -50,8 +50,8 @@
|
|||
<!ENTITY netTimeout.title "Network Timeout">
|
||||
<!ENTITY netTimeout.longDesc "<p>The requested site did not respond to a connection request and the browser has stopped waiting for a reply.</p><ul><li>Could the server be experiencing high demand or a temporary outage? Try again later.</li><li>Are you unable to browse other sites? Check the computer's network connection.</li><li>Is your computer or network protected by a firewall or proxy? Incorrect settings can interfere with Web browsing.</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>">
|
||||
|
||||
<!ENTITY protocolNotFound.title "Unknown Protocol">
|
||||
<!ENTITY protocolNotFound.longDesc "<p>The address specifies a protocol (e.g. <q>wxyz://</q>) the browser does not recognize, so the browser cannot properly connect to the site.</p><ul><li>Are you trying to access multimedia or other non-text services? Check the site for extra requirements.</li><li>Some protocols may require third-party software or plugins before the browser can recognize them.</li></ul>">
|
||||
<!ENTITY unknownProtocolFound.title "Unknown Protocol">
|
||||
<!ENTITY unknownProtocolFound.longDesc "<p>The address specifies a protocol (e.g. <q>wxyz://</q>) the browser does not recognize, so the browser cannot properly connect to the site.</p><ul><li>Are you trying to access multimedia or other non-text services? Check the site for extra requirements.</li><li>Some protocols may require third-party software or plugins before the browser can recognize them.</li></ul>">
|
||||
|
||||
<!ENTITY proxyConnectFailure.title "Proxy Server Refused Connection">
|
||||
<!ENTITY proxyConnectFailure.longDesc "<p>The browser is configured to use a proxy server, but the proxy refused a connection.</p><ul><li>Is the browser's proxy configuration correct? Check the settings and try again.</li><li>Does the proxy service allow connections from this network?</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>">
|
||||
|
|
|
@ -716,6 +716,21 @@ APZCTreeManager::DispatchScroll(AsyncPanZoomController* aPrev, ScreenPoint aStar
|
|||
next->AttemptScroll(aStartPoint, aEndPoint, aOverscrollHandoffChainIndex);
|
||||
}
|
||||
|
||||
bool
|
||||
APZCTreeManager::FlushRepaintsForOverscrollHandoffChain()
|
||||
{
|
||||
if (mOverscrollHandoffChain.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < mOverscrollHandoffChain.length(); i++) {
|
||||
nsRefPtr<AsyncPanZoomController> item = mOverscrollHandoffChain[i];
|
||||
if (item) {
|
||||
item->FlushRepaintForOverscrollHandoff();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
|
||||
{
|
||||
|
|
|
@ -256,6 +256,8 @@ public:
|
|||
void DispatchScroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
|
||||
uint32_t aOverscrollHandoffChainIndex);
|
||||
|
||||
bool FlushRepaintsForOverscrollHandoffChain();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Debug-build assertion that can be called to ensure code is running on the
|
||||
|
|
|
@ -575,16 +575,18 @@ nsEventStatus AsyncPanZoomController::ReceiveInputEvent(const InputData& aEvent)
|
|||
nsEventStatus AsyncPanZoomController::HandleInputEvent(const InputData& aEvent) {
|
||||
nsEventStatus rv = nsEventStatus_eIgnore;
|
||||
|
||||
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
|
||||
if (listener) {
|
||||
rv = listener->HandleInputEvent(aEvent);
|
||||
if (rv == nsEventStatus_eConsumeNoDefault)
|
||||
return rv;
|
||||
}
|
||||
|
||||
switch (aEvent.mInputType) {
|
||||
case MULTITOUCH_INPUT: {
|
||||
const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
|
||||
|
||||
nsRefPtr<GestureEventListener> listener = GetGestureEventListener();
|
||||
if (listener) {
|
||||
rv = listener->HandleInputEvent(multiTouchInput);
|
||||
if (rv == nsEventStatus_eConsumeNoDefault) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
switch (multiTouchInput.mType) {
|
||||
case MultiTouchInput::MULTITOUCH_START: rv = OnTouchStart(multiTouchInput); break;
|
||||
case MultiTouchInput::MULTITOUCH_MOVE: rv = OnTouchMove(multiTouchInput); break;
|
||||
|
@ -757,9 +759,17 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
|||
case PANNING_LOCKED_X:
|
||||
case PANNING_LOCKED_Y:
|
||||
{
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
// Make a local copy of the tree manager pointer and check if it's not
|
||||
// null before calling HandleOverscroll(). This is necessary because
|
||||
// Destroy(), which nulls out mTreeManager, could be called concurrently.
|
||||
APZCTreeManager* treeManagerLocal = mTreeManager;
|
||||
if (treeManagerLocal) {
|
||||
if (!treeManagerLocal->FlushRepaintsForOverscrollHandoffChain()) {
|
||||
NS_WARNING("Overscroll handoff chain was empty during panning! This should not be the case.");
|
||||
// Graceful handling of error condition
|
||||
FlushRepaintForOverscrollHandoff();
|
||||
}
|
||||
}
|
||||
}
|
||||
mX.EndTouch();
|
||||
mY.EndTouch();
|
||||
|
@ -1389,6 +1399,12 @@ void AsyncPanZoomController::ScheduleComposite() {
|
|||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::FlushRepaintForOverscrollHandoff() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
RequestContentRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::RequestContentRepaint() {
|
||||
RequestContentRepaint(mFrameMetrics);
|
||||
}
|
||||
|
|
|
@ -333,6 +333,8 @@ public:
|
|||
*/
|
||||
bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; }
|
||||
|
||||
void FlushRepaintForOverscrollHandoff();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Helper method for touches beginning. Sets everything up for panning and any
|
||||
|
|
|
@ -48,26 +48,20 @@ GestureEventListener::~GestureEventListener()
|
|||
{
|
||||
}
|
||||
|
||||
nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
||||
nsEventStatus GestureEventListener::HandleInputEvent(const MultiTouchInput& aEvent)
|
||||
{
|
||||
if (aEvent.mInputType != MULTITOUCH_INPUT) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
const MultiTouchInput& event = static_cast<const MultiTouchInput&>(aEvent);
|
||||
|
||||
// Cache the current event since it may become the single or long tap that we
|
||||
// send.
|
||||
mLastTouchInput = event;
|
||||
mLastTouchInput = aEvent;
|
||||
|
||||
switch (event.mType)
|
||||
switch (aEvent.mType)
|
||||
{
|
||||
case MultiTouchInput::MULTITOUCH_START:
|
||||
case MultiTouchInput::MULTITOUCH_ENTER: {
|
||||
for (size_t i = 0; i < event.mTouches.Length(); i++) {
|
||||
for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
|
||||
bool foundAlreadyExistingTouch = false;
|
||||
for (size_t j = 0; j < mTouches.Length(); j++) {
|
||||
if (mTouches[j].mIdentifier == event.mTouches[i].mIdentifier) {
|
||||
if (mTouches[j].mIdentifier == aEvent.mTouches[i].mIdentifier) {
|
||||
foundAlreadyExistingTouch = true;
|
||||
break;
|
||||
}
|
||||
|
@ -75,14 +69,14 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
|
||||
// If we didn't find a touch in our list that matches this, then add it.
|
||||
if (!foundAlreadyExistingTouch) {
|
||||
mTouches.AppendElement(event.mTouches[i]);
|
||||
mTouches.AppendElement(aEvent.mTouches[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t length = mTouches.Length();
|
||||
if (length == 1) {
|
||||
mTapStartTime = event.mTime;
|
||||
mTouchStartPosition = event.mTouches[0].mScreenPoint;
|
||||
mTapStartTime = aEvent.mTime;
|
||||
mTouchStartPosition = aEvent.mTouches[0].mScreenPoint;
|
||||
if (mState == GESTURE_NONE) {
|
||||
mState = GESTURE_WAITING_SINGLE_TAP;
|
||||
|
||||
|
@ -95,28 +89,28 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
}
|
||||
} else if (length == 2) {
|
||||
// Another finger has been added; it can't be a tap anymore.
|
||||
HandleTapCancel(event);
|
||||
HandleTapCancel(aEvent);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MultiTouchInput::MULTITOUCH_MOVE: {
|
||||
// If we move too much, bail out of the tap.
|
||||
ScreenIntPoint delta = event.mTouches[0].mScreenPoint - mTouchStartPosition;
|
||||
ScreenIntPoint delta = aEvent.mTouches[0].mScreenPoint - mTouchStartPosition;
|
||||
if (mTouches.Length() == 1 &&
|
||||
NS_hypot(delta.x, delta.y) > AsyncPanZoomController::GetTouchStartTolerance())
|
||||
{
|
||||
HandleTapCancel(event);
|
||||
HandleTapCancel(aEvent);
|
||||
}
|
||||
|
||||
size_t eventTouchesMatched = 0;
|
||||
for (size_t i = 0; i < mTouches.Length(); i++) {
|
||||
bool isTouchRemoved = true;
|
||||
for (size_t j = 0; j < event.mTouches.Length(); j++) {
|
||||
if (mTouches[i].mIdentifier == event.mTouches[j].mIdentifier) {
|
||||
for (size_t j = 0; j < aEvent.mTouches.Length(); j++) {
|
||||
if (mTouches[i].mIdentifier == aEvent.mTouches[j].mIdentifier) {
|
||||
eventTouchesMatched++;
|
||||
isTouchRemoved = false;
|
||||
mTouches[i] = event.mTouches[j];
|
||||
mTouches[i] = aEvent.mTouches[j];
|
||||
}
|
||||
}
|
||||
if (isTouchRemoved) {
|
||||
|
@ -126,16 +120,16 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
}
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(eventTouchesMatched == event.mTouches.Length(), "Touch moved, but not in list");
|
||||
NS_WARN_IF_FALSE(eventTouchesMatched == aEvent.mTouches.Length(), "Touch moved, but not in list");
|
||||
|
||||
break;
|
||||
}
|
||||
case MultiTouchInput::MULTITOUCH_END:
|
||||
case MultiTouchInput::MULTITOUCH_LEAVE: {
|
||||
for (size_t i = 0; i < event.mTouches.Length(); i++) {
|
||||
for (size_t i = 0; i < aEvent.mTouches.Length(); i++) {
|
||||
bool foundAlreadyExistingTouch = false;
|
||||
for (size_t j = 0; j < mTouches.Length() && !foundAlreadyExistingTouch; j++) {
|
||||
if (event.mTouches[i].mIdentifier == mTouches[j].mIdentifier) {
|
||||
if (aEvent.mTouches[i].mIdentifier == mTouches[j].mIdentifier) {
|
||||
foundAlreadyExistingTouch = true;
|
||||
mTouches.RemoveElementAt(j);
|
||||
}
|
||||
|
@ -146,30 +140,30 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
if (mState == GESTURE_WAITING_DOUBLE_TAP) {
|
||||
CancelDoubleTapTimeoutTask();
|
||||
if (mTapStartTime - mLastTapEndTime > MAX_TAP_TIME ||
|
||||
event.mTime - mTapStartTime > MAX_TAP_TIME) {
|
||||
aEvent.mTime - mTapStartTime > MAX_TAP_TIME) {
|
||||
// Either the time between taps or the last tap took too long
|
||||
// confirm previous tap and handle current tap seperately
|
||||
TimeoutDoubleTap();
|
||||
mState = GESTURE_WAITING_SINGLE_TAP;
|
||||
} else {
|
||||
// We were waiting for a double tap and it has arrived.
|
||||
HandleDoubleTap(event);
|
||||
HandleDoubleTap(aEvent);
|
||||
mState = GESTURE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == GESTURE_LONG_TAP_UP) {
|
||||
HandleLongTapUpEvent(event);
|
||||
HandleLongTapUpEvent(aEvent);
|
||||
mState = GESTURE_NONE;
|
||||
} else if (mState == GESTURE_WAITING_SINGLE_TAP &&
|
||||
event.mTime - mTapStartTime > MAX_TAP_TIME) {
|
||||
aEvent.mTime - mTapStartTime > MAX_TAP_TIME) {
|
||||
// Extended taps are immediately dispatched as single taps
|
||||
CancelLongTapTimeoutTask();
|
||||
HandleSingleTapConfirmedEvent(event);
|
||||
HandleSingleTapConfirmedEvent(aEvent);
|
||||
mState = GESTURE_NONE;
|
||||
} else if (mState == GESTURE_WAITING_SINGLE_TAP) {
|
||||
CancelLongTapTimeoutTask();
|
||||
nsEventStatus tapupEvent = HandleSingleTapUpEvent(event);
|
||||
nsEventStatus tapupEvent = HandleSingleTapUpEvent(aEvent);
|
||||
|
||||
if (tapupEvent == nsEventStatus_eIgnore) {
|
||||
// We were not waiting for anything but a single tap has happened that
|
||||
|
@ -190,7 +184,7 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
}
|
||||
}
|
||||
|
||||
mLastTapEndTime = event.mTime;
|
||||
mLastTapEndTime = aEvent.mTime;
|
||||
|
||||
if (!mTouches.Length()) {
|
||||
mSpanChange = 0.0f;
|
||||
|
@ -199,20 +193,24 @@ nsEventStatus GestureEventListener::HandleInputEvent(const InputData& aEvent)
|
|||
break;
|
||||
}
|
||||
case MultiTouchInput::MULTITOUCH_CANCEL:
|
||||
// This gets called if there's a touch that has to bail for weird reasons
|
||||
// like pinching and then moving away from the window that the pinch was
|
||||
// started in without letting go of the screen.
|
||||
return HandlePinchGestureEvent(event, true);
|
||||
// FIXME: we should probably clear a bunch of gesture state here
|
||||
break;
|
||||
}
|
||||
|
||||
return HandlePinchGestureEvent(event, false);
|
||||
return HandlePinchGestureEvent(aEvent);
|
||||
}
|
||||
|
||||
nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInput& aEvent, bool aClearTouches)
|
||||
nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInput& aEvent)
|
||||
{
|
||||
nsEventStatus rv = nsEventStatus_eIgnore;
|
||||
|
||||
if (mTouches.Length() > 1 && !aClearTouches) {
|
||||
if (aEvent.mType == MultiTouchInput::MULTITOUCH_CANCEL) {
|
||||
mTouches.Clear();
|
||||
mState = GESTURE_NONE;
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mTouches.Length() > 1) {
|
||||
const ScreenIntPoint& firstTouch = mTouches[0].mScreenPoint,
|
||||
secondTouch = mTouches[1].mScreenPoint;
|
||||
ScreenPoint focusPoint = ScreenPoint(firstTouch + secondTouch) / 2;
|
||||
|
@ -289,10 +287,6 @@ nsEventStatus GestureEventListener::HandlePinchGestureEvent(const MultiTouchInpu
|
|||
mState = GESTURE_NONE;
|
||||
}
|
||||
|
||||
if (aClearTouches) {
|
||||
mTouches.Clear();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
* of a gesture, then we pass it along to AsyncPanZoomController. Otherwise,
|
||||
* it gets consumed here and never forwarded along.
|
||||
*/
|
||||
nsEventStatus HandleInputEvent(const InputData& aEvent);
|
||||
nsEventStatus HandleInputEvent(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Cancels any currently active gesture. May not properly handle situations
|
||||
|
@ -94,11 +94,8 @@ protected:
|
|||
/**
|
||||
* Attempts to handle the event as a pinch event. If it is not a pinch event,
|
||||
* then we simply tell the next consumer to consume the event instead.
|
||||
*
|
||||
* |aClearTouches| marks whether or not to terminate any pinch currently
|
||||
* happening.
|
||||
*/
|
||||
nsEventStatus HandlePinchGestureEvent(const MultiTouchInput& aEvent, bool aClearTouches);
|
||||
nsEventStatus HandlePinchGestureEvent(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Attempts to handle the event as a single tap event, which highlights links
|
||||
|
|
|
@ -170,10 +170,10 @@ SetScriptSourceFilename(ExclusiveContext *cx, ScriptSource *ss,
|
|||
{
|
||||
if (options.hasIntroductionInfo) {
|
||||
const char *filename = options.filename() ? options.filename() : "<unknown>";
|
||||
JS_ASSERT(options.introducer != nullptr);
|
||||
JS_ASSERT(options.introductionType != nullptr);
|
||||
|
||||
if (!ss->setIntroducedFilename(cx, filename, options.introductionLineno,
|
||||
options.introducer, options.introducerFilename()))
|
||||
options.introductionType, options.introducerFilename()))
|
||||
return false;
|
||||
|
||||
ss->setIntroductionOffset(options.introductionOffset);
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// Check that scripts' introduction types are properly marked.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
var log;
|
||||
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, 'eval');
|
||||
};
|
||||
log = '';
|
||||
g.eval('debugger;');
|
||||
assertEq(log, 'd');
|
||||
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, 'Function');
|
||||
};
|
||||
log = '';
|
||||
g.Function('debugger;')();
|
||||
assertEq(log, 'd');
|
||||
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, 'GeneratorFunction');
|
||||
};
|
||||
log = '';
|
||||
g.eval('(function*() {})').constructor('debugger;')().next();
|
||||
assertEq(log, 'd');
|
||||
|
||||
dbg.onDebuggerStatement = function (frame) {
|
||||
log += 'd';
|
||||
assertEq(frame.script.source.introductionType, undefined);
|
||||
};
|
||||
log = '';
|
||||
g.evaluate('debugger;');
|
||||
assertEq(log, 'd');
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
if (getBuildConfiguration().parallelJS) {
|
||||
var map_toSource_called = false;
|
||||
var mapPar_toSource_called = false;
|
||||
|
||||
Array.prototype.mapPar.toSource = function() {
|
||||
mapPar_toSource_called = true;
|
||||
};
|
||||
|
||||
Array.prototype.map.toSource = function() {
|
||||
map_toSource_called = true;
|
||||
};
|
||||
|
||||
try { new Array.prototype.mapPar; } catch (e) {}
|
||||
try { new Array.prototype.map; } catch (e) {}
|
||||
|
||||
assertEq(map_toSource_called, mapPar_toSource_called);
|
||||
}
|
|
@ -236,17 +236,25 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
|
|||
heap = &bufferVal.toObject().as<ArrayBufferObject>();
|
||||
|
||||
if (!IsValidAsmJSHeapLength(heap->byteLength())) {
|
||||
return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next valid length is 0x%x",
|
||||
heap->byteLength(),
|
||||
RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
|
||||
ScopedJSFreePtr<char> msg(
|
||||
JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
|
||||
"valid length is 0x%x",
|
||||
heap->byteLength(),
|
||||
RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
|
||||
return LinkFail(cx, msg.get());
|
||||
}
|
||||
|
||||
// This check is sufficient without considering the size of the loaded datum because heap
|
||||
// loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
|
||||
JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
|
||||
if (heap->byteLength() < module.minHeapLength()) {
|
||||
return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the largest constant heap access offset rounded up to the next valid heap size).",
|
||||
heap->byteLength(), module.minHeapLength()));
|
||||
ScopedJSFreePtr<char> msg(
|
||||
JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the"
|
||||
"largest constant heap access offset rounded up to the next valid "
|
||||
"heap size).",
|
||||
heap->byteLength(),
|
||||
module.minHeapLength()));
|
||||
return LinkFail(cx, msg.get());
|
||||
}
|
||||
|
||||
if (!ArrayBufferObject::prepareForAsmJS(cx, heap))
|
||||
|
|
|
@ -285,7 +285,7 @@ CanEnterBaselineJIT(JSContext *cx, HandleScript script, bool osr)
|
|||
if (script->isCallsiteClone()) {
|
||||
// Ensure the original function is compiled too, so that bailouts from
|
||||
// Ion code have a BaselineScript to resume into.
|
||||
RootedScript original(cx, script->originalFunction()->nonLazyScript());
|
||||
RootedScript original(cx, script->donorFunction()->nonLazyScript());
|
||||
JS_ASSERT(original != script);
|
||||
|
||||
if (!original->canBaselineCompile())
|
||||
|
|
|
@ -23,10 +23,13 @@ BEGIN_TEST(testGCStoreBufferRemoval)
|
|||
CHECK(!js::gc::IsInsideNursery(rt, obj.get()));
|
||||
JS::RootedObject tenuredObject(cx, obj);
|
||||
|
||||
// Hide the horrors herein from the static rooting analysis.
|
||||
typedef JSObject *ObjectPtr;
|
||||
|
||||
// Test removal of store buffer entries added by RelocatablePtr<T>.
|
||||
{
|
||||
JSObject *badObject = reinterpret_cast<JSObject*>(1);
|
||||
JSObject *punnedPtr = nullptr;
|
||||
ObjectPtr badObject = reinterpret_cast<JSObject*>(1);
|
||||
ObjectPtr punnedPtr = nullptr;
|
||||
RelocatablePtrObject* relocPtr =
|
||||
reinterpret_cast<RelocatablePtrObject*>(&punnedPtr);
|
||||
new (relocPtr) RelocatablePtrObject;
|
||||
|
@ -77,8 +80,8 @@ BEGIN_TEST(testGCStoreBufferRemoval)
|
|||
|
||||
// Test removal of store buffer entries added by Heap<T>.
|
||||
{
|
||||
JSObject *badObject = reinterpret_cast<JSObject*>(1);
|
||||
JSObject *punnedPtr = nullptr;
|
||||
ObjectPtr badObject = reinterpret_cast<JSObject*>(1);
|
||||
ObjectPtr punnedPtr = nullptr;
|
||||
Heap<JSObject*>* heapPtr =
|
||||
reinterpret_cast<Heap<JSObject*>*>(&punnedPtr);
|
||||
new (heapPtr) Heap<JSObject*>;
|
||||
|
|
|
@ -4312,7 +4312,7 @@ JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions &rhs)
|
|||
werrorOption = rhs.werrorOption;
|
||||
asmJSOption = rhs.asmJSOption;
|
||||
sourcePolicy = rhs.sourcePolicy;
|
||||
introducer = rhs.introducer;
|
||||
introductionType = rhs.introductionType;
|
||||
introductionLineno = rhs.introductionLineno;
|
||||
introductionOffset = rhs.introductionOffset;
|
||||
hasIntroductionInfo = rhs.hasIntroductionInfo;
|
||||
|
|
|
@ -3478,7 +3478,7 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
|
|||
asmJSOption(false),
|
||||
forceAsync(false),
|
||||
sourcePolicy(SAVE_SOURCE),
|
||||
introducer(nullptr),
|
||||
introductionType(nullptr),
|
||||
introductionLineno(0),
|
||||
introductionOffset(0),
|
||||
hasIntroductionInfo(false)
|
||||
|
@ -3521,9 +3521,9 @@ class JS_FRIEND_API(ReadOnlyCompileOptions)
|
|||
SAVE_SOURCE
|
||||
} sourcePolicy;
|
||||
|
||||
// |introducer| is a statically allocated C string:
|
||||
// |introductionType| is a statically allocated C string:
|
||||
// one of "eval", "Function", or "GeneratorFunction".
|
||||
const char *introducer;
|
||||
const char *introductionType;
|
||||
unsigned introductionLineno;
|
||||
uint32_t introductionOffset;
|
||||
bool hasIntroductionInfo;
|
||||
|
@ -3616,7 +3616,7 @@ class JS_FRIEND_API(OwningCompileOptions) : public ReadOnlyCompileOptions
|
|||
{
|
||||
if (!setIntroducerFilename(cx, introducerFn))
|
||||
return false;
|
||||
introducer = intro;
|
||||
introductionType = intro;
|
||||
introductionLineno = line;
|
||||
introductionOffset = offset;
|
||||
hasIntroductionInfo = true;
|
||||
|
@ -3692,7 +3692,7 @@ class MOZ_STACK_CLASS JS_FRIEND_API(CompileOptions) : public ReadOnlyCompileOpti
|
|||
unsigned line, uint32_t offset)
|
||||
{
|
||||
introducerFilename_ = introducerFn;
|
||||
introducer = intro;
|
||||
introductionType = intro;
|
||||
introductionLineno = line;
|
||||
introductionOffset = offset;
|
||||
hasIntroductionInfo = true;
|
||||
|
|
|
@ -118,8 +118,8 @@ fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValu
|
|||
|
||||
/* Callsite clones should never escape to script. */
|
||||
JSObject &maybeClone = iter.calleev().toObject();
|
||||
if (maybeClone.is<JSFunction>() && maybeClone.as<JSFunction>().nonLazyScript()->isCallsiteClone())
|
||||
vp.setObject(*maybeClone.as<JSFunction>().nonLazyScript()->originalFunction());
|
||||
if (maybeClone.is<JSFunction>())
|
||||
vp.setObject(*maybeClone.as<JSFunction>().originalFunction());
|
||||
else
|
||||
vp.set(iter.calleev());
|
||||
|
||||
|
@ -1486,9 +1486,9 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
|
|||
CurrentScriptFileLineOrigin(cx, &script, &filename, &lineno, &pcOffset, &originPrincipals);
|
||||
JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
|
||||
|
||||
const char *introducer = "Function";
|
||||
const char *introductionType = "Function";
|
||||
if (generatorKind != NotGenerator)
|
||||
introducer = "GeneratorFunction";
|
||||
introductionType = "GeneratorFunction";
|
||||
|
||||
const char *introducerFilename = filename;
|
||||
if (script && script->scriptSource()->introducerFilename())
|
||||
|
@ -1500,7 +1500,7 @@ FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind gener
|
|||
.setFileAndLine(filename, 1)
|
||||
.setNoScriptRval(false)
|
||||
.setCompileAndGo(true)
|
||||
.setIntroductionInfo(introducerFilename, introducer, lineno, pcOffset);
|
||||
.setIntroductionInfo(introducerFilename, introductionType, lineno, pcOffset);
|
||||
|
||||
unsigned n = args.length() ? args.length() - 1 : 0;
|
||||
if (n > 0) {
|
||||
|
|
|
@ -339,6 +339,16 @@ class JSFunction : public JSObject
|
|||
return u.i.s.script_;
|
||||
}
|
||||
|
||||
// Returns non-callsited-clone version of this. Use when return
|
||||
// value can flow to arbitrary JS (see Bug 944975).
|
||||
JSFunction* originalFunction() {
|
||||
if (this->hasScript() && this->nonLazyScript()->isCallsiteClone()) {
|
||||
return this->nonLazyScript()->donorFunction();
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
js::HeapPtrScript &mutableScript() {
|
||||
JS_ASSERT(isInterpreted());
|
||||
return *(js::HeapPtrScript *)&u.i.s.script_;
|
||||
|
|
|
@ -1599,12 +1599,12 @@ ScriptSource::displayURL()
|
|||
bool
|
||||
ScriptSource::setIntroducedFilename(ExclusiveContext *cx,
|
||||
const char *callerFilename, unsigned callerLineno,
|
||||
const char *introducer, const char *introducerFilename)
|
||||
const char *introductionType, const char *introducerFilename)
|
||||
{
|
||||
JS_ASSERT(!filename_);
|
||||
JS_ASSERT(!introducerFilename_);
|
||||
|
||||
introducerType_ = introducer;
|
||||
introductionType_ = introductionType;
|
||||
|
||||
if (introducerFilename) {
|
||||
introducerFilename_ = js_strdup(cx, introducerFilename);
|
||||
|
@ -1612,24 +1612,24 @@ ScriptSource::setIntroducedFilename(ExclusiveContext *cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Final format: "{callerFilename} line {callerLineno} > {introducer}"
|
||||
// Final format: "{callerFilename} line {callerLineno} > {introductionType}"
|
||||
// Len = strlen(callerFilename) + strlen(" line ") +
|
||||
// strlen(toStr(callerLineno)) + strlen(" > ") + strlen(introducer);
|
||||
// strlen(toStr(callerLineno)) + strlen(" > ") + strlen(introductionType);
|
||||
char linenoBuf[15];
|
||||
size_t filenameLen = strlen(callerFilename);
|
||||
size_t linenoLen = JS_snprintf(linenoBuf, 15, "%u", callerLineno);
|
||||
size_t introducerLen = strlen(introducer);
|
||||
size_t introductionTypeLen = strlen(introductionType);
|
||||
size_t len = filenameLen +
|
||||
6 /* == strlen(" line ") */ +
|
||||
linenoLen +
|
||||
3 /* == strlen(" > ") */ +
|
||||
introducerLen +
|
||||
introductionTypeLen +
|
||||
1 /* \0 */;
|
||||
filename_ = cx->pod_malloc<char>(len);
|
||||
if (!filename_)
|
||||
return false;
|
||||
mozilla::DebugOnly<int> checkLen = JS_snprintf(filename_, len, "%s line %s > %s",
|
||||
callerFilename, linenoBuf, introducer);
|
||||
callerFilename, linenoBuf, introductionType);
|
||||
JS_ASSERT(checkLen == len - 1);
|
||||
|
||||
if (!introducerFilename_)
|
||||
|
|
|
@ -405,7 +405,7 @@ class ScriptSource
|
|||
// undefined if the implementation doesn't know how the code was introduced.
|
||||
// This is a constant, statically allocated C string, so does not need
|
||||
// memory management.
|
||||
const char *introducerType_;
|
||||
const char *introductionType_;
|
||||
|
||||
// True if we can call JSRuntime::sourceHook to load the source on
|
||||
// demand. If sourceRetrievable_ and hasSourceData() are false, it is not
|
||||
|
@ -426,7 +426,7 @@ class ScriptSource
|
|||
originPrincipals_(originPrincipals),
|
||||
introductionOffset_(0),
|
||||
introducerFilename_(nullptr),
|
||||
introducerType_(nullptr),
|
||||
introductionType_(nullptr),
|
||||
sourceRetrievable_(false),
|
||||
argumentsNotIncluded_(false),
|
||||
ready_(true),
|
||||
|
@ -471,16 +471,16 @@ class ScriptSource
|
|||
bool setFilename(ExclusiveContext *cx, const char *filename);
|
||||
bool setIntroducedFilename(ExclusiveContext *cx,
|
||||
const char *callerFilename, unsigned callerLineno,
|
||||
const char *introducer, const char *introducerFilename);
|
||||
const char *introductionType, const char *introducerFilename);
|
||||
const char *introducerFilename() const {
|
||||
return introducerFilename_;
|
||||
}
|
||||
bool hasIntroducerType() const {
|
||||
return introducerType_;
|
||||
bool hasIntroductionType() const {
|
||||
return introductionType_;
|
||||
}
|
||||
const char *introducerType() const {
|
||||
JS_ASSERT(hasIntroducerType());
|
||||
return introducerType_;
|
||||
const char *introductionType() const {
|
||||
JS_ASSERT(hasIntroductionType());
|
||||
return introductionType_;
|
||||
}
|
||||
const char *filename() const {
|
||||
return filename_;
|
||||
|
@ -1273,7 +1273,10 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
|
|||
*/
|
||||
inline void ensureNonLazyCanonicalFunction(JSContext *cx);
|
||||
|
||||
JSFunction *originalFunction() const;
|
||||
/*
|
||||
* Donor provided itself to callsite clone; null if this is non-clone.
|
||||
*/
|
||||
JSFunction *donorFunction() const;
|
||||
void setIsCallsiteClone(JSObject *fun);
|
||||
|
||||
JSFlatString *sourceData(JSContext *cx);
|
||||
|
|
|
@ -149,7 +149,7 @@ JSScript::principals()
|
|||
}
|
||||
|
||||
inline JSFunction *
|
||||
JSScript::originalFunction() const {
|
||||
JSScript::donorFunction() const {
|
||||
if (!isCallsiteClone())
|
||||
return nullptr;
|
||||
return &enclosingScopeOrOriginalFunction_->as<JSFunction>();
|
||||
|
|
|
@ -3937,8 +3937,8 @@ DebuggerSource_getIntroductionType(JSContext *cx, unsigned argc, Value *vp)
|
|||
THIS_DEBUGSOURCE_REFERENT(cx, argc, vp, "(get introductionOffset)", args, obj, sourceObject);
|
||||
|
||||
ScriptSource *ss = sourceObject->source();
|
||||
if (ss->hasIntroducerType()) {
|
||||
JSString *str = js_NewStringCopyZ<CanGC>(cx, ss->introducerType());
|
||||
if (ss->hasIntroductionType()) {
|
||||
JSString *str = js_NewStringCopyZ<CanGC>(cx, ss->introductionType());
|
||||
if (!str)
|
||||
return false;
|
||||
args.rval().setString(str);
|
||||
|
|
|
@ -555,9 +555,10 @@ js::InvokeConstructor(JSContext *cx, CallArgs args)
|
|||
return ok;
|
||||
}
|
||||
|
||||
if (!fun->isInterpretedConstructor())
|
||||
return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
|
||||
|
||||
if (!fun->isInterpretedConstructor()) {
|
||||
RootedValue orig(cx, ObjectValue(*fun->originalFunction()));
|
||||
return ReportIsNotFunction(cx, orig, args.length() + 1, CONSTRUCT);
|
||||
}
|
||||
if (!Invoke(cx, args, CONSTRUCT))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -203,101 +203,6 @@ nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
aAttribute, aModType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterFrame::PaintFilteredFrame(nsRenderingContext *aContext,
|
||||
nsIFrame *aFilteredFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsRect *aDirtyArea,
|
||||
nsIFrame* aTransformRoot)
|
||||
{
|
||||
nsSVGFilterInstance instance(aFilteredFrame, this, aPaintCallback,
|
||||
aDirtyArea, nullptr, nullptr, nullptr,
|
||||
aTransformRoot);
|
||||
if (!instance.IsInitialized()) {
|
||||
return NS_OK;
|
||||
}
|
||||
return instance.Render(aContext->ThebesContext());
|
||||
}
|
||||
|
||||
static nsRect
|
||||
TransformFilterSpaceToFrameSpace(nsSVGFilterInstance *aInstance,
|
||||
nsIntRect *aRect)
|
||||
{
|
||||
if (aRect->IsEmpty()) {
|
||||
return nsRect();
|
||||
}
|
||||
gfxMatrix m = aInstance->GetFilterSpaceToFrameSpaceInCSSPxTransform();
|
||||
gfxRect r(aRect->x, aRect->y, aRect->width, aRect->height);
|
||||
r = m.TransformBounds(r);
|
||||
return nsLayoutUtils::RoundGfxRectToAppRect(r, aInstance->AppUnitsPerCSSPixel());
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterFrame::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPreFilterDirtyRect)
|
||||
{
|
||||
if (aPreFilterDirtyRect.IsEmpty()) {
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsSVGFilterInstance instance(aFilteredFrame, this, nullptr, nullptr,
|
||||
&aPreFilterDirtyRect);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
// We've passed in the source's dirty area so the instance knows about it.
|
||||
// Now we can ask the instance to compute the area of the filter output
|
||||
// that's dirty.
|
||||
nsIntRect dirtyRect;
|
||||
nsresult rv = instance.ComputePostFilterDirtyRect(&dirtyRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return TransformFilterSpaceToFrameSpace(&instance, &dirtyRect);
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterFrame::GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPostFilterDirtyRect)
|
||||
{
|
||||
nsSVGFilterInstance instance(aFilteredFrame, this, nullptr,
|
||||
&aPostFilterDirtyRect);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
// Now we can ask the instance to compute the area of the source
|
||||
// that's needed.
|
||||
nsIntRect neededRect;
|
||||
nsresult rv = instance.ComputeSourceNeededRect(&neededRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return TransformFilterSpaceToFrameSpace(&instance, &neededRect);
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterFrame::GetPostFilterBounds(nsIFrame *aFilteredFrame,
|
||||
const gfxRect *aOverrideBBox,
|
||||
const nsRect *aPreFilterBounds)
|
||||
{
|
||||
MOZ_ASSERT(!(aFilteredFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
|
||||
!(aFilteredFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
|
||||
"Non-display SVG do not maintain visual overflow rects");
|
||||
|
||||
nsSVGFilterInstance instance(aFilteredFrame, this, nullptr, nullptr,
|
||||
aPreFilterBounds, aPreFilterBounds,
|
||||
aOverrideBBox);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
nsIntRect bbox;
|
||||
nsresult rv = instance.ComputePostFilterExtents(&bbox);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return TransformFilterSpaceToFrameSpace(&instance, &bbox);
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsSVGFilterFrame::Init(nsIContent* aContent,
|
||||
|
|
|
@ -57,48 +57,6 @@ public:
|
|||
nsIAtom* aAttribute,
|
||||
int32_t aModType) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* Paint the given filtered frame.
|
||||
* @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
|
||||
* frame space (i.e. relative to its origin, the top-left corner of its
|
||||
* border box).
|
||||
*/
|
||||
nsresult PaintFilteredFrame(nsRenderingContext *aContext,
|
||||
nsIFrame *aFilteredFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsRect* aDirtyArea,
|
||||
nsIFrame* aTransformRoot);
|
||||
|
||||
/**
|
||||
* Returns the post-filter area that could be dirtied when the given
|
||||
* pre-filter area of aFilteredFrame changes.
|
||||
* @param aPreFilterDirtyRect The pre-filter area of aFilteredFrame that has
|
||||
* changed, relative to aFilteredFrame, in app units.
|
||||
*/
|
||||
nsRect GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPreFilterDirtyRect);
|
||||
|
||||
/**
|
||||
* Returns the pre-filter area that is needed from aFilteredFrame when the
|
||||
* given post-filter area needs to be repainted.
|
||||
* @param aPostFilterDirtyRect The post-filter area that is dirty, relative
|
||||
* to aFilteredFrame, in app units.
|
||||
*/
|
||||
nsRect GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPostFilterDirtyRect);
|
||||
|
||||
/**
|
||||
* Returns the post-filter visual overflow rect (paint bounds) of
|
||||
* aFilteredFrame.
|
||||
* @param aOverrideBBox A user space rect, in user units, that should be used
|
||||
* as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
|
||||
* @param aPreFilterBounds The pre-filter visual overflow rect of
|
||||
* aFilteredFrame, if non-null.
|
||||
*/
|
||||
nsRect GetPostFilterBounds(nsIFrame *aFilteredFrame,
|
||||
const gfxRect *aOverrideBBox = nullptr,
|
||||
const nsRect *aPreFilterBounds = nullptr);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void Init(nsIContent* aContent,
|
||||
nsIFrame* aParent,
|
||||
|
|
|
@ -23,6 +23,92 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::PaintFilteredFrame(nsSVGFilterFrame* aFilterFrame,
|
||||
nsRenderingContext *aContext,
|
||||
nsIFrame *aFilteredFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsRect *aDirtyArea,
|
||||
nsIFrame* aTransformRoot)
|
||||
{
|
||||
nsSVGFilterInstance instance(aFilteredFrame, aFilterFrame, aPaintCallback,
|
||||
aDirtyArea, nullptr, nullptr, nullptr,
|
||||
aTransformRoot);
|
||||
if (!instance.IsInitialized()) {
|
||||
return NS_OK;
|
||||
}
|
||||
return instance.Render(aContext->ThebesContext());
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterInstance::GetPostFilterDirtyArea(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPreFilterDirtyRect)
|
||||
{
|
||||
if (aPreFilterDirtyRect.IsEmpty()) {
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsSVGFilterInstance instance(aFilteredFrame, aFilterFrame, nullptr, nullptr,
|
||||
&aPreFilterDirtyRect);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
// We've passed in the source's dirty area so the instance knows about it.
|
||||
// Now we can ask the instance to compute the area of the filter output
|
||||
// that's dirty.
|
||||
nsRect dirtyRect;
|
||||
nsresult rv = instance.ComputePostFilterDirtyRect(&dirtyRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return dirtyRect;
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterInstance::GetPreFilterNeededArea(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPostFilterDirtyRect)
|
||||
{
|
||||
nsSVGFilterInstance instance(aFilteredFrame, aFilterFrame, nullptr,
|
||||
&aPostFilterDirtyRect);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
// Now we can ask the instance to compute the area of the source
|
||||
// that's needed.
|
||||
nsRect neededRect;
|
||||
nsresult rv = instance.ComputeSourceNeededRect(&neededRect);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return neededRect;
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterInstance::GetPostFilterBounds(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const gfxRect *aOverrideBBox,
|
||||
const nsRect *aPreFilterBounds)
|
||||
{
|
||||
MOZ_ASSERT(!(aFilteredFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
|
||||
!(aFilteredFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
|
||||
"Non-display SVG do not maintain visual overflow rects");
|
||||
|
||||
nsSVGFilterInstance instance(aFilteredFrame, aFilterFrame, nullptr, nullptr,
|
||||
aPreFilterBounds, aPreFilterBounds,
|
||||
aOverrideBBox);
|
||||
if (!instance.IsInitialized()) {
|
||||
return nsRect();
|
||||
}
|
||||
nsRect bbox;
|
||||
nsresult rv = instance.ComputePostFilterExtents(&bbox);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return bbox;
|
||||
}
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
nsSVGFilterInstance::nsSVGFilterInstance(nsIFrame *aTargetFrame,
|
||||
nsSVGFilterFrame *aFilterFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
|
@ -664,9 +750,9 @@ nsSVGFilterInstance::Render(gfxContext* aContext)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::ComputePostFilterDirtyRect(nsIntRect* aPostFilterDirtyRect)
|
||||
nsSVGFilterInstance::ComputePostFilterDirtyRect(nsRect* aPostFilterDirtyRect)
|
||||
{
|
||||
*aPostFilterDirtyRect = nsIntRect();
|
||||
*aPostFilterDirtyRect = nsRect();
|
||||
if (mPreFilterDirtyRect.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -685,14 +771,15 @@ nsSVGFilterInstance::ComputePostFilterDirtyRect(nsIntRect* aPostFilterDirtyRect)
|
|||
nsIntRegion resultChangeRegion =
|
||||
FilterSupport::ComputeResultChangeRegion(filter,
|
||||
mPreFilterDirtyRect, nsIntRegion(), nsIntRegion());
|
||||
*aPostFilterDirtyRect = resultChangeRegion.GetBounds();
|
||||
*aPostFilterDirtyRect =
|
||||
FilterSpaceToFrameSpace(resultChangeRegion.GetBounds());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::ComputePostFilterExtents(nsIntRect* aPostFilterExtents)
|
||||
nsSVGFilterInstance::ComputePostFilterExtents(nsRect* aPostFilterExtents)
|
||||
{
|
||||
*aPostFilterExtents = nsIntRect();
|
||||
*aPostFilterExtents = nsRect();
|
||||
|
||||
nsresult rv = BuildPrimitives();
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -714,12 +801,12 @@ nsSVGFilterInstance::ComputePostFilterExtents(nsIntRect* aPostFilterExtents)
|
|||
FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
|
||||
nsIntRegion postFilterExtents =
|
||||
FilterSupport::ComputePostFilterExtents(filter, sourceBoundsInt);
|
||||
*aPostFilterExtents = postFilterExtents.GetBounds();
|
||||
*aPostFilterExtents = FilterSpaceToFrameSpace(postFilterExtents.GetBounds());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSVGFilterInstance::ComputeSourceNeededRect(nsIntRect* aDirty)
|
||||
nsSVGFilterInstance::ComputeSourceNeededRect(nsRect* aDirty)
|
||||
{
|
||||
nsresult rv = BuildPrimitives();
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -731,7 +818,7 @@ nsSVGFilterInstance::ComputeSourceNeededRect(nsIntRect* aDirty)
|
|||
}
|
||||
|
||||
ComputeNeededBoxes();
|
||||
*aDirty = mSourceGraphic.mNeededBounds;
|
||||
*aDirty = FilterSpaceToFrameSpace(mSourceGraphic.mNeededBounds);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -757,6 +844,17 @@ nsSVGFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const
|
|||
return rect;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return nsRect();
|
||||
}
|
||||
gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r);
|
||||
return nsLayoutUtils::RoundGfxRectToAppRect(r, mAppUnitsPerCSSPx);
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
nsSVGFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform() const
|
||||
{
|
||||
|
|
|
@ -59,6 +59,52 @@ class nsSVGFilterInstance
|
|||
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Paint the given filtered frame.
|
||||
* @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
|
||||
* frame space (i.e. relative to its origin, the top-left corner of its
|
||||
* border box).
|
||||
*/
|
||||
static nsresult PaintFilteredFrame(nsSVGFilterFrame* aFilterFrame,
|
||||
nsRenderingContext *aContext,
|
||||
nsIFrame *aFilteredFrame,
|
||||
nsSVGFilterPaintCallback *aPaintCallback,
|
||||
const nsRect* aDirtyArea,
|
||||
nsIFrame* aTransformRoot = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the post-filter area that could be dirtied when the given
|
||||
* pre-filter area of aFilteredFrame changes.
|
||||
* @param aPreFilterDirtyRect The pre-filter area of aFilteredFrame that has
|
||||
* changed, relative to aFilteredFrame, in app units.
|
||||
*/
|
||||
static nsRect GetPostFilterDirtyArea(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPreFilterDirtyRect);
|
||||
|
||||
/**
|
||||
* Returns the pre-filter area that is needed from aFilteredFrame when the
|
||||
* given post-filter area needs to be repainted.
|
||||
* @param aPostFilterDirtyRect The post-filter area that is dirty, relative
|
||||
* to aFilteredFrame, in app units.
|
||||
*/
|
||||
static nsRect GetPreFilterNeededArea(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const nsRect& aPostFilterDirtyRect);
|
||||
|
||||
/**
|
||||
* Returns the post-filter visual overflow rect (paint bounds) of
|
||||
* aFilteredFrame.
|
||||
* @param aOverrideBBox A user space rect, in user units, that should be used
|
||||
* as aFilteredFrame's bbox ('bbox' is a specific SVG term), if non-null.
|
||||
* @param aPreFilterBounds The pre-filter visual overflow rect of
|
||||
* aFilteredFrame, if non-null.
|
||||
*/
|
||||
static nsRect GetPostFilterBounds(nsSVGFilterFrame* aFilterFrame,
|
||||
nsIFrame *aFilteredFrame,
|
||||
const gfxRect *aOverrideBBox = nullptr,
|
||||
const nsRect *aPreFilterBounds = nullptr);
|
||||
|
||||
/**
|
||||
* @param aTargetFrame The frame of the filtered element under consideration.
|
||||
* @param aFilterFrame The frame of the SVG filter element.
|
||||
|
@ -118,31 +164,31 @@ public:
|
|||
nsresult Render(gfxContext* aContext);
|
||||
|
||||
/**
|
||||
* Sets the aPostFilterDirtyRect outparam to the post-filter bounds in filter
|
||||
* Sets the aPostFilterDirtyRect outparam to the post-filter bounds in frame
|
||||
* space of the area that would be dirtied by mTargetFrame when a given
|
||||
* pre-filter area of mTargetFrame is dirtied. The pre-filter area must have
|
||||
* been specified before calling this method by passing it as the
|
||||
* aPreFilterDirtyRect argument to the nsSVGFilterInstance constructor.
|
||||
*/
|
||||
nsresult ComputePostFilterDirtyRect(nsIntRect* aPostFilterDirtyRect);
|
||||
nsresult ComputePostFilterDirtyRect(nsRect* aPostFilterDirtyRect);
|
||||
|
||||
/**
|
||||
* Sets the aPostFilterExtents outparam to the post-filter bounds in filter
|
||||
* Sets the aPostFilterExtents outparam to the post-filter bounds in frame
|
||||
* space for the whole filter output. This is not necessarily equivalent to
|
||||
* the area that would be dirtied in the result when the entire pre-filter
|
||||
* area is dirtied, because some filter primitives can generate output
|
||||
* without any input.
|
||||
*/
|
||||
nsresult ComputePostFilterExtents(nsIntRect* aPostFilterExtents);
|
||||
nsresult ComputePostFilterExtents(nsRect* aPostFilterExtents);
|
||||
|
||||
/**
|
||||
* Sets the aDirty outparam to the pre-filter bounds in filter space of the
|
||||
* Sets the aDirty outparam to the pre-filter bounds in frame space of the
|
||||
* area of mTargetFrame that is needed in order to paint the filtered output
|
||||
* for a given post-filter dirtied area. The post-filter area must have been
|
||||
* specified before calling this method by passing it as the aPostFilterDirtyRect
|
||||
* argument to the nsSVGFilterInstance constructor.
|
||||
*/
|
||||
nsresult ComputeSourceNeededRect(nsIntRect* aDirty);
|
||||
nsresult ComputeSourceNeededRect(nsRect* aDirty);
|
||||
|
||||
float GetPrimitiveNumber(uint8_t aCtxType, const nsSVGNumber2 *aNumber) const
|
||||
{
|
||||
|
@ -269,6 +315,7 @@ private:
|
|||
* large to be stored in an nsIntRect.
|
||||
*/
|
||||
nsIntRect FrameSpaceToFilterSpace(const nsRect* aRect) const;
|
||||
nsRect FilterSpaceToFrameSpace(const nsIntRect& aRect) const;
|
||||
|
||||
/**
|
||||
* Returns the transform from frame space to the coordinate space that
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "nsSVGEffects.h"
|
||||
#include "nsSVGElement.h"
|
||||
#include "nsSVGFilterFrame.h"
|
||||
#include "nsSVGFilterInstance.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
#include "nsSVGMaskFrame.h"
|
||||
#include "nsSVGPaintServerFrame.h"
|
||||
|
@ -276,7 +277,7 @@ nsRect
|
|||
overrideBBox.RoundOut();
|
||||
|
||||
nsRect overflowRect =
|
||||
filterFrame->GetPostFilterBounds(firstFrame, &overrideBBox);
|
||||
nsSVGFilterInstance::GetPostFilterBounds(filterFrame, firstFrame, &overrideBBox);
|
||||
|
||||
// Return overflowRect relative to aFrame, rather than "user space":
|
||||
return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToUserSpace);
|
||||
|
@ -327,8 +328,8 @@ nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame,
|
|||
|
||||
// Adjust the dirty area for effects, and shift it back to being relative to
|
||||
// the reference frame.
|
||||
nsRect result = filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect) -
|
||||
toUserSpace;
|
||||
nsRect result = nsSVGFilterInstance::GetPostFilterDirtyArea(filterFrame,
|
||||
firstFrame, preEffectsRect) - toUserSpace;
|
||||
// Return the result, in pixels relative to the reference frame.
|
||||
return result.ToOutsidePixels(appUnitsPerDevPixel);
|
||||
}
|
||||
|
@ -352,8 +353,8 @@ nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(nsIFrame* aFrame,
|
|||
nsRect postEffectsRect = aDirtyRect + toUserSpace;
|
||||
|
||||
// Return ther result, relative to aFrame, not in user space:
|
||||
return filterFrame->GetPreFilterNeededArea(firstFrame, postEffectsRect) -
|
||||
toUserSpace;
|
||||
return nsSVGFilterInstance::GetPreFilterNeededArea(filterFrame, firstFrame,
|
||||
postEffectsRect) - toUserSpace;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -517,7 +518,8 @@ nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
|
|||
RegularFramePaintCallback callback(aBuilder, aLayerManager,
|
||||
offsetWithoutSVGGeomFramePos);
|
||||
nsRect dirtyRect = aDirtyRect - offset;
|
||||
filterFrame->PaintFilteredFrame(aCtx, aFrame, &callback, &dirtyRect, nullptr);
|
||||
nsSVGFilterInstance::PaintFilteredFrame(filterFrame, aCtx, aFrame,
|
||||
&callback, &dirtyRect);
|
||||
} else {
|
||||
gfx->SetMatrix(matrixAutoSaveRestore.Matrix());
|
||||
aLayerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder);
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "nsSVGContainerFrame.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "nsSVGFilterFrame.h"
|
||||
#include "nsSVGFilterInstance.h"
|
||||
#include "nsSVGFilterPaintCallback.h"
|
||||
#include "nsSVGForeignObjectFrame.h"
|
||||
#include "gfxSVGGlyphs.h"
|
||||
|
@ -159,12 +160,13 @@ nsSVGUtils::GetPostFilterVisualOverflowRect(nsIFrame *aFrame,
|
|||
NS_ABORT_IF_FALSE(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT,
|
||||
"Called on invalid frame type");
|
||||
|
||||
nsSVGFilterFrame *filter = nsSVGEffects::GetFilterFrame(aFrame);
|
||||
if (!filter) {
|
||||
nsSVGFilterFrame *filterFrame = nsSVGEffects::GetFilterFrame(aFrame);
|
||||
if (!filterFrame) {
|
||||
return aPreFilterRect;
|
||||
}
|
||||
|
||||
return filter->GetPostFilterBounds(aFrame, nullptr, &aPreFilterRect);
|
||||
return nsSVGFilterInstance::GetPostFilterBounds(filterFrame, aFrame, nullptr,
|
||||
&aPreFilterRect);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -621,7 +623,9 @@ nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
|
|||
dirtyRect = &tmpDirtyRect;
|
||||
}
|
||||
SVGPaintCallback paintCallback;
|
||||
filterFrame->PaintFilteredFrame(aContext, aFrame, &paintCallback, dirtyRect, aTransformRoot);
|
||||
nsSVGFilterInstance::PaintFilteredFrame(filterFrame, aContext, aFrame,
|
||||
&paintCallback, dirtyRect,
|
||||
aTransformRoot);
|
||||
} else {
|
||||
svgChildFrame->PaintSVG(aContext, aDirtyRect, aTransformRoot);
|
||||
}
|
||||
|
|
|
@ -1198,6 +1198,9 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
|||
nsDeviceContext* devContext = presContext->DeviceContext();
|
||||
nscoord offsetForContextMenu = 0;
|
||||
|
||||
bool isNoAutoHide = IsNoAutoHide();
|
||||
nsPopupLevel popupLevel = PopupLevel(isNoAutoHide);
|
||||
|
||||
if (IsAnchored()) {
|
||||
// if we are anchored, there are certain things we don't want to do when
|
||||
// repositioning the popup to fit on the screen, such as end up positioned
|
||||
|
@ -1238,7 +1241,7 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
|||
// the window is moved. Popups at the parent level follow the parent
|
||||
// window as it is moved and remained anchored, so we want to maintain the
|
||||
// anchoring instead.
|
||||
if (IsNoAutoHide() && PopupLevel(true) != ePopupLevelParent) {
|
||||
if (isNoAutoHide && popupLevel != ePopupLevelParent) {
|
||||
// Account for the margin that will end up being added to the screen coordinate
|
||||
// the next time SetPopupPosition is called.
|
||||
mScreenXPos = presContext->AppUnitsToIntCSSPixels(screenPoint.x - margin.left);
|
||||
|
@ -1279,7 +1282,7 @@ nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove, bool aS
|
|||
// If a panel is being moved or has flip="none", don't constrain or flip it. But always do this for
|
||||
// content shells, so that the popup doesn't extend outside the containing frame.
|
||||
if (mInContentShell || (mFlip != FlipType_None && (!aIsMove || mPopupType != ePopupTypePanel))) {
|
||||
nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect);
|
||||
nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect, popupLevel);
|
||||
|
||||
// Ensure that anchorRect is on screen.
|
||||
anchorRect = anchorRect.Intersect(screenRect);
|
||||
|
@ -1378,7 +1381,8 @@ nsMenuPopupFrame::GetCurrentMenuItem()
|
|||
|
||||
nsRect
|
||||
nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
|
||||
const nsRect& aRootScreenRect)
|
||||
const nsRect& aRootScreenRect,
|
||||
nsPopupLevel aPopupLevel)
|
||||
{
|
||||
nsIntRect screenRectPixels;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
@ -1401,8 +1405,11 @@ nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
|
|||
nsPresContext::AppUnitsToIntCSSPixels(rect.y),
|
||||
width, height, getter_AddRefs(screen));
|
||||
if (screen) {
|
||||
// Non-top-level popups (which will always be panels)
|
||||
// should never overlap the OS bar:
|
||||
bool dontOverlapOSBar = aPopupLevel != ePopupLevelTop;
|
||||
// get the total screen area if the popup is allowed to overlap it.
|
||||
if (mMenuCanOverlapOSBar && !mInContentShell)
|
||||
if (!dontOverlapOSBar && mMenuCanOverlapOSBar && !mInContentShell)
|
||||
screen->GetRect(&screenRectPixels.x, &screenRectPixels.y,
|
||||
&screenRectPixels.width, &screenRectPixels.height);
|
||||
else
|
||||
|
|
|
@ -310,7 +310,11 @@ public:
|
|||
// area of the screen the popup should be displayed on. Content popups,
|
||||
// however, will also be constrained by the content area, given by
|
||||
// aRootScreenRect. All coordinates are in app units.
|
||||
nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect);
|
||||
// For non-toplevel popups (which will always be panels), we will also
|
||||
// constrain them to the available screen rect, ie they will not fall
|
||||
// underneath the taskbar, dock or other fixed OS elements.
|
||||
nsRect GetConstraintRect(const nsRect& aAnchorRect, const nsRect& aRootScreenRect,
|
||||
nsPopupLevel aPopupLevel);
|
||||
|
||||
// Determines whether the given edges of the popup may be moved, where
|
||||
// aHorizontalSide and aVerticalSide are one of the NS_SIDE_* constants, or
|
||||
|
|
|
@ -224,7 +224,8 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
nsIFrame* rootFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
|
||||
nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();
|
||||
|
||||
nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect);
|
||||
nsPopupLevel popupLevel = menuPopupFrame->PopupLevel();
|
||||
nsRect screenRect = menuPopupFrame->GetConstraintRect(frameRect, rootScreenRect, popupLevel);
|
||||
// round using ToInsidePixels as it's better to be a pixel too small
|
||||
// than be too large. If the popup is too large it could get flipped
|
||||
// to the opposite side of the anchor point while resizing.
|
||||
|
|
|
@ -73,8 +73,10 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
|
|||
{
|
||||
delete mRecvCodecList[i];
|
||||
}
|
||||
|
||||
delete mCurSendCodecConfig;
|
||||
if (mPtrVoERTP_RTCP) {
|
||||
mPtrVoERTP_RTCP->Release();
|
||||
}
|
||||
|
||||
// The first one of a pair to be deleted shuts down media for both
|
||||
if(mPtrVoEXmedia)
|
||||
|
@ -278,19 +280,22 @@ MediaConduitErrorCode WebrtcAudioConduit::Init(WebrtcAudioConduit *other)
|
|||
CSFLogError(logTag, "%s Unable to initialize VoEProcessing", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
}
|
||||
|
||||
if(!(mPtrVoEXmedia = VoEExternalMedia::GetInterface(mVoiceEngine)))
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to initialize VoEExternalMedia", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
}
|
||||
if(!(mPtrVoERTP_RTCP = VoERTP_RTCP::GetInterface(mVoiceEngine)))
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to initialize VoERTP_RTCP", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
}
|
||||
|
||||
if(!(mPtrVoEVideoSync = VoEVideoSync::GetInterface(mVoiceEngine)))
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to initialize VoEVideoSync", __FUNCTION__);
|
||||
return kMediaConduitSessionNotInited;
|
||||
}
|
||||
|
||||
if (!(mPtrRTP = webrtc::VoERTP_RTCP::GetInterface(mVoiceEngine)))
|
||||
{
|
||||
CSFLogError(logTag, "%s Unable to get audio RTP/RTCP interface ",
|
||||
|
@ -556,12 +561,24 @@ WebrtcAudioConduit::ConfigureRecvMediaCodecs(
|
|||
CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
|
||||
return kMediaConduitPlayoutError;
|
||||
}
|
||||
|
||||
//we should be good here for setting this.
|
||||
mEngineReceiving = true;
|
||||
DumpCodecDB();
|
||||
return kMediaConduitNoError;
|
||||
}
|
||||
MediaConduitErrorCode
|
||||
WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
|
||||
{
|
||||
CSFLogDebug(logTag, "%s %d %d ", __FUNCTION__, enabled, id);
|
||||
|
||||
if (mPtrVoERTP_RTCP->SetRTPAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
|
||||
{
|
||||
CSFLogError(logTag, "%s SetRTPAudioLevelIndicationStatus Failed", __FUNCTION__);
|
||||
return kMediaConduitUnknownError;
|
||||
}
|
||||
|
||||
return kMediaConduitNoError;
|
||||
}
|
||||
|
||||
MediaConduitErrorCode
|
||||
WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
|
||||
|
@ -570,7 +587,6 @@ WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
|
|||
int32_t capture_delay)
|
||||
{
|
||||
CSFLogDebug(logTag, "%s ", __FUNCTION__);
|
||||
|
||||
// Following checks need to be performed
|
||||
// 1. Non null audio buffer pointer,
|
||||
// 2. invalid sampling frequency - less than 0 or unsupported ones
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "webrtc/voice_engine/include/voe_audio_processing.h"
|
||||
#include "webrtc/voice_engine/include/voe_video_sync.h"
|
||||
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
|
||||
|
||||
//Some WebRTC types for short notations
|
||||
using webrtc::VoEBase;
|
||||
using webrtc::VoENetwork;
|
||||
|
@ -31,13 +30,11 @@
|
|||
using webrtc::VoEExternalMedia;
|
||||
using webrtc::VoEAudioProcessing;
|
||||
using webrtc::VoEVideoSync;
|
||||
|
||||
using webrtc::VoERTP_RTCP;
|
||||
/** This file hosts several structures identifying different aspects
|
||||
* of a RTP Session.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Helper function
|
||||
|
||||
DOMHighResTimeStamp
|
||||
|
@ -86,13 +83,17 @@ public:
|
|||
*/
|
||||
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
|
||||
const std::vector<AudioCodecConfig* >& codecConfigList);
|
||||
/**
|
||||
* Function to enable the audio level extension
|
||||
* @param enabled: enable extension
|
||||
*/
|
||||
virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled, uint8_t id);
|
||||
|
||||
/**
|
||||
* Register External Transport to this Conduit. RTP and RTCP frames from the VoiceEngine
|
||||
* shall be passed to the registered transport for transporting externally.
|
||||
*/
|
||||
virtual MediaConduitErrorCode AttachTransport(mozilla::RefPtr<TransportInterface> aTransport);
|
||||
|
||||
/**
|
||||
* Function to deliver externally captured audio sample for encoding and transport
|
||||
* @param audioData [in]: Pointer to array containing a frame of audio
|
||||
|
@ -234,13 +235,12 @@ private:
|
|||
webrtc::VoEExternalMedia* mPtrVoEXmedia;
|
||||
webrtc::VoEAudioProcessing* mPtrVoEProcessing;
|
||||
webrtc::VoEVideoSync* mPtrVoEVideoSync;
|
||||
webrtc::VoERTP_RTCP* mPtrVoERTP_RTCP;
|
||||
webrtc::VoERTP_RTCP* mPtrRTP;
|
||||
|
||||
//engine states of our interets
|
||||
bool mEngineTransmitting; // If true => VoiceEngine Send-subsystem is up
|
||||
bool mEngineReceiving; // If true => VoiceEngine Receive-subsystem is up
|
||||
// and playout is enabled
|
||||
|
||||
// Keep track of each inserted RTP block and the time it was inserted
|
||||
// so we can estimate the clock time for a specific TimeStamp coming out
|
||||
// (for when we send data to MediaStreamTracks). Blocks are aged out as needed.
|
||||
|
|
|
@ -344,16 +344,18 @@ public:
|
|||
*/
|
||||
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
|
||||
const std::vector<AudioCodecConfig* >& recvCodecConfigList) = 0;
|
||||
/**
|
||||
* Function to enable the audio level extension
|
||||
* @param enabled: enable extension
|
||||
* @param id: id to be used for this rtp header extension
|
||||
* NOTE: See AudioConduit for more information
|
||||
*/
|
||||
virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled, uint8_t id) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2230,12 +2230,15 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id,
|
|||
// and are responsible for cleanly shutting down.
|
||||
mozilla::RefPtr<mozilla::AudioSessionConduit> conduit =
|
||||
mozilla::AudioSessionConduit::Create(static_cast<AudioSessionConduit *>(rx_conduit.get()));
|
||||
|
||||
if (!conduit || conduit->ConfigureSendMediaCodec(config))
|
||||
return VCM_ERROR;
|
||||
CSFLogError(logTag, "Created audio pipeline audio level %d %d",
|
||||
attrs->audio_level, attrs->audio_level_id);
|
||||
|
||||
if (!conduit || conduit->EnableAudioLevelExtension(attrs->audio_level, attrs->audio_level_id))
|
||||
return VCM_ERROR;
|
||||
|
||||
pc.impl()->media()->AddConduit(level, false, conduit);
|
||||
|
||||
mozilla::RefPtr<mozilla::MediaPipeline> pipeline =
|
||||
new mozilla::MediaPipelineTransmit(
|
||||
pc.impl()->GetHandle(),
|
||||
|
|
|
@ -514,17 +514,16 @@ gsmsdp_init_media (fsmdef_media_t *media)
|
|||
media->previous_sdp.num_payloads = 0;
|
||||
media->previous_sdp.tias_bw = SDP_INVALID_VALUE;
|
||||
media->previous_sdp.profile_level = 0;
|
||||
|
||||
media->hold = FSM_HOLD_NONE;
|
||||
media->flags = 0; /* clear all flags */
|
||||
media->cap_index = CC_MAX_MEDIA_CAP; /* max is invalid value */
|
||||
media->video = NULL;
|
||||
media->candidate_ct = 0;
|
||||
media->rtcp_mux = FALSE;
|
||||
|
||||
media->audio_level = TRUE;
|
||||
media->audio_level_id = 1;
|
||||
/* ACTPASS is the value we put in every offer */
|
||||
media->setup = SDP_SETUP_ACTPASS;
|
||||
|
||||
media->local_datachannel_port = 0;
|
||||
media->remote_datachannel_port = 0;
|
||||
media->datachannel_streams = WEBRTC_DATACHANNEL_STREAMS_DEFAULT;
|
||||
|
@ -1702,7 +1701,6 @@ gsmsdp_set_rtcp_fb_ack_attribute (uint16_t level,
|
|||
GSM_ERR_MSG("Failed to add attribute");
|
||||
return;
|
||||
}
|
||||
|
||||
result = sdp_attr_set_rtcp_fb_ack(sdp_p, level, payload_type,
|
||||
a_instance, ack_type);
|
||||
if (result != SDP_SUCCESS) {
|
||||
|
@ -1710,6 +1708,39 @@ gsmsdp_set_rtcp_fb_ack_attribute (uint16_t level,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gsmsdp_set_audio_level_attribute
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Adds an audio level extension attributesto the specified SDP.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* level - The media level of the SDP where the media attribute exists.
|
||||
* sdp_p - Pointer to the SDP to set the attribute against.
|
||||
*/
|
||||
void
|
||||
gsmsdp_set_extmap_attribute (uint16_t level,
|
||||
void *sdp_p,
|
||||
u16 id,
|
||||
const char* uri)
|
||||
{
|
||||
uint16_t a_instance = 0;
|
||||
sdp_result_e result;
|
||||
|
||||
result = sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, &a_instance);
|
||||
if (result != SDP_SUCCESS) {
|
||||
GSM_ERR_MSG("Failed to add attribute");
|
||||
return;
|
||||
}
|
||||
|
||||
result = sdp_attr_set_extmap(sdp_p, level, id, uri, a_instance);
|
||||
if (result != SDP_SUCCESS) {
|
||||
GSM_ERR_MSG("Failed to set attribute");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gsmsdp_set_rtcp_fb_nack_attribute
|
||||
*
|
||||
|
@ -4629,6 +4660,66 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_sdp_p,
|
|||
}
|
||||
}
|
||||
}
|
||||
return CC_CAUSE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* gsmsdp_negotiate_extmap
|
||||
*
|
||||
* Description:
|
||||
* Negotiates extmaps header extension to local SDP for supported audio codecs
|
||||
*
|
||||
* Parameters:
|
||||
* cc_sdp_p - local and remote SDP
|
||||
* media - The media structure for the current level to be negotiated
|
||||
* offer - True if the remote SDP is an offer
|
||||
*
|
||||
* returns
|
||||
* CC_CAUSE_OK - success
|
||||
* any other code - failure
|
||||
*/
|
||||
cc_causes_t
|
||||
gsmsdp_negotiate_extmap (cc_sdp_t *cc_sdp_p,
|
||||
fsmdef_media_t *media,
|
||||
boolean offer)
|
||||
{
|
||||
boolean audio_level = FALSE;
|
||||
u16 audio_level_id = 0xFFFF;
|
||||
int level = media->level;
|
||||
int i;
|
||||
const char* uri;
|
||||
|
||||
/*
|
||||
* Remove any previously negotiated extmap attributes from the
|
||||
* local SDP
|
||||
*/
|
||||
sdp_result_e result = SDP_SUCCESS;
|
||||
while (result == SDP_SUCCESS) {
|
||||
result = sdp_delete_attr (cc_sdp_p->src_sdp, level, 0,
|
||||
SDP_ATTR_EXTMAP, 1);
|
||||
}
|
||||
|
||||
i = 1;
|
||||
do {
|
||||
uri = sdp_attr_get_extmap_uri(cc_sdp_p->dest_sdp, level, i);
|
||||
|
||||
if (uri != NULL && strcmp(uri, SDP_EXTMAP_AUDIO_LEVEL) == 0) {
|
||||
audio_level = TRUE;
|
||||
audio_level_id = sdp_attr_get_extmap_id(cc_sdp_p->dest_sdp, level, i);
|
||||
}
|
||||
i++;
|
||||
} while (uri != NULL);
|
||||
|
||||
media->audio_level = audio_level;
|
||||
media->audio_level_id = audio_level_id;
|
||||
|
||||
/*
|
||||
* Now, in our local SDP, set extmap types that both we and the
|
||||
* remote party support
|
||||
*/
|
||||
if (media->audio_level) {
|
||||
gsmsdp_set_extmap_attribute (level, cc_sdp_p->src_sdp, audio_level_id, SDP_EXTMAP_AUDIO_LEVEL);
|
||||
}
|
||||
|
||||
return CC_CAUSE_OK;
|
||||
}
|
||||
|
@ -4980,11 +5071,14 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean initial
|
|||
unsupported_line = TRUE;
|
||||
update_local_ret_value = TRUE;
|
||||
}
|
||||
|
||||
/* Negotiate rtcp feedback mechanisms */
|
||||
if (media && media_type == SDP_MEDIA_VIDEO) {
|
||||
gsmsdp_negotiate_rtcp_fb (dcb_p->sdp, media, offer);
|
||||
}
|
||||
/* Negotiate redundancy mechanisms */
|
||||
if (media && media_type == SDP_MEDIA_AUDIO) {
|
||||
gsmsdp_negotiate_extmap (dcb_p->sdp, media, offer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Negotiate rtcp-mux
|
||||
|
@ -4993,7 +5087,6 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean initial
|
|||
sdp_res = sdp_attr_get_rtcp_mux_attribute(sdp_p->dest_sdp, i,
|
||||
0, SDP_ATTR_RTCP_MUX,
|
||||
1, &rtcp_mux);
|
||||
|
||||
if (SDP_SUCCESS == sdp_res) {
|
||||
media->rtcp_mux = TRUE;
|
||||
}
|
||||
|
@ -5597,10 +5690,14 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap,
|
|||
sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) |
|
||||
sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR));
|
||||
}
|
||||
/* Add supported audio level rtp extension */
|
||||
if (media_cap->type == SDP_MEDIA_AUDIO) {
|
||||
gsmsdp_set_extmap_attribute(level, dcb_p->sdp->src_sdp, 1,
|
||||
SDP_EXTMAP_AUDIO_LEVEL);
|
||||
}
|
||||
|
||||
/* Add a=setup attribute */
|
||||
gsmsdp_set_setup_attribute(level, dcb_p->sdp->src_sdp, media->setup);
|
||||
|
||||
/*
|
||||
* wait until here to set ICE candidates as SDP is now initialized
|
||||
*/
|
||||
|
|
|
@ -201,17 +201,21 @@ typedef struct fsmdef_media_t_ {
|
|||
/* ICE Candidates */
|
||||
char **candidatesp;
|
||||
int candidate_ct;
|
||||
|
||||
/*
|
||||
* rtcp-mux indicates media stream is muxed for RTP and RTCP
|
||||
*/
|
||||
boolean rtcp_mux;
|
||||
/*
|
||||
* Flag to indicate if RTP Header extension for audio level is used
|
||||
* and the id to be used for it
|
||||
*/
|
||||
boolean audio_level;
|
||||
uint8_t audio_level_id;
|
||||
|
||||
/*
|
||||
* The value of the a=setup line
|
||||
*/
|
||||
sdp_setup_type_e setup;
|
||||
|
||||
/*
|
||||
* port number used in m= data channel line
|
||||
*/
|
||||
|
|
|
@ -1230,13 +1230,11 @@ lsm_tx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
media->xmit_chan = TRUE;
|
||||
|
||||
attrs.mute = FALSE;
|
||||
|
||||
attrs.rtcp_mux = media->rtcp_mux;
|
||||
|
||||
attrs.audio_level = media->audio_level;
|
||||
attrs.audio_level_id = (uint8_t)media->audio_level_id;
|
||||
attrs.is_video = FALSE;
|
||||
attrs.bundle_level = 0;
|
||||
attrs.bundle_stream_correlator = 0;
|
||||
|
|
|
@ -67,15 +67,14 @@
|
|||
#define SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE(cw) \
|
||||
((cw) |= (SDP_SRTP_ENCRYPT_MASK | SDP_SRTP_AUTHENTICATE_MASK | \
|
||||
SDP_SRTCP_ENCRYPT_MASK))
|
||||
|
||||
#define SDP_SRTP_CONTEXT_RESET_SSRC(cw) ((cw) &= ~(SDP_SRTCP_SSRC_MASK))
|
||||
#define SDP_SRTP_CONTEXT_RESET_ROC(cw) ((cw) &= ~(SDP_SRTCP_ROC_MASK))
|
||||
#define SDP_SRTP_CONTEXT_RESET_KDR(cw) ((cw) &= ~(SDP_SRTCP_KDR_MASK))
|
||||
#define SDP_CONTEXT_RESET_MASTER_KEY(cw) ((cw) &= ~(SDP_SRTCP_KEY_MASK))
|
||||
#define SDP_CONTEXT_RESET_MASTER_SALT(cw) ((cw) &= ~(SDP_SRTCP_SALT_MASK))
|
||||
#define SDP_EXTMAP_AUDIO_LEVEL "urn:ietf:params:rtp-hdrext:ssrc-audio-level"
|
||||
|
||||
/* SDP Enum Types */
|
||||
|
||||
typedef enum {
|
||||
SDP_DEBUG_TRACE,
|
||||
SDP_DEBUG_WARNINGS,
|
||||
|
@ -892,6 +891,16 @@ typedef struct sdp_media_profiles {
|
|||
sdp_payload_ind_e payload_indicator[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
|
||||
u16 payload_type[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
|
||||
} sdp_media_profiles_t;
|
||||
/*
|
||||
* a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
|
||||
*
|
||||
*/
|
||||
typedef struct sdp_extmap {
|
||||
u16 id;
|
||||
sdp_direction_e media_direction;
|
||||
char uri[SDP_MAX_STRING_LEN+1];
|
||||
char extension_attributes[SDP_MAX_STRING_LEN+1];
|
||||
} sdp_extmap_t;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -899,7 +908,6 @@ typedef struct sdp_media_profiles {
|
|||
* This type is used to hold cryptographic context information.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct sdp_srtp_crypto_context_t_ {
|
||||
int32 tag;
|
||||
unsigned long selection_flags;
|
||||
|
@ -982,10 +990,10 @@ typedef struct sdp_attr {
|
|||
sdp_fmtp_fb_t rtcp_fb;
|
||||
sdp_setup_type_e setup;
|
||||
sdp_connection_type_e connection;
|
||||
sdp_extmap_t extmap;
|
||||
} attr;
|
||||
struct sdp_attr *next_p;
|
||||
} sdp_attr_t;
|
||||
|
||||
typedef struct sdp_srtp_crypto_suite_list_ {
|
||||
sdp_srtp_crypto_suite_t crypto_suite_val;
|
||||
char * crypto_suite_str;
|
||||
|
@ -2099,9 +2107,16 @@ sdp_attr_set_rtcp_fb_nack(void *sdp_ptr, u16 level, u16 payload_type, u16 inst,
|
|||
sdp_result_e
|
||||
sdp_attr_set_rtcp_fb_trr_int(void *sdp_ptr, u16 level, u16 payload_type,
|
||||
u16 inst, u32 interval);
|
||||
|
||||
sdp_result_e
|
||||
sdp_attr_set_rtcp_fb_ccm(void *sdp_ptr, u16 level, u16 payload_type, u16 inst,
|
||||
sdp_rtcp_fb_ccm_type_e);
|
||||
const char *
|
||||
sdp_attr_get_extmap_uri(void *sdp_ptr, u16 level, u16 inst);
|
||||
|
||||
u16
|
||||
sdp_attr_get_extmap_id(void *sdp_ptr, u16 level, u16 inst);
|
||||
|
||||
sdp_result_e
|
||||
sdp_attr_set_extmap(void *sdp_ptr, u16 level, u16 id, const char* uri, u16 inst);
|
||||
|
||||
#endif /* _SDP_H_ */
|
||||
|
|
|
@ -5145,6 +5145,79 @@ sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
|
|||
return SDP_FAILURE;
|
||||
break;
|
||||
}
|
||||
return SDP_SUCCESS;
|
||||
}
|
||||
|
||||
sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
flex_string *fs)
|
||||
{
|
||||
flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
|
||||
attr_p->attr.extmap.id,
|
||||
attr_p->attr.extmap.uri);
|
||||
|
||||
return SDP_SUCCESS;
|
||||
}
|
||||
|
||||
sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
const char *ptr)
|
||||
{
|
||||
sdp_result_e result;
|
||||
|
||||
attr_p->attr.extmap.id = 0;
|
||||
attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
|
||||
attr_p->attr.extmap.uri[0] = '\0';
|
||||
attr_p->attr.extmap.extension_attributes[0] = '\0';
|
||||
|
||||
/* Find the payload type number. */
|
||||
attr_p->attr.extmap.id =
|
||||
(u16)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
|
||||
if (result != SDP_SUCCESS) {
|
||||
sdp_parse_error(sdp_p->peerconnection,
|
||||
"%s Warning: Invalid extmap id specified for %s attribute.",
|
||||
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (*ptr == '/') {
|
||||
char direction[SDP_MAX_STRING_LEN+1];
|
||||
/* Find the encoding name. */
|
||||
ptr = sdp_getnextstrtok(ptr, direction,
|
||||
sizeof(direction), " \t", &result);
|
||||
if (result != SDP_SUCCESS) {
|
||||
sdp_parse_error(sdp_p->peerconnection,
|
||||
"%s Warning: No uri specified in %s attribute.",
|
||||
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri,
|
||||
sizeof(attr_p->attr.extmap.uri), " \t", &result);
|
||||
if (result != SDP_SUCCESS) {
|
||||
sdp_parse_error(sdp_p->peerconnection,
|
||||
"%s Warning: No uri specified in %s attribute.",
|
||||
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes,
|
||||
sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
|
||||
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
||||
SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
|
||||
"uri %s, extension %s", sdp_p->debug_str,
|
||||
sdp_get_attr_name(attr_p->type),
|
||||
attr_p->attr.extmap.id,
|
||||
SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
|
||||
attr_p->attr.extmap.uri,
|
||||
attr_p->attr.extmap.extension_attributes);
|
||||
}
|
||||
|
||||
return (SDP_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
|
@ -12477,10 +12477,112 @@ sdp_attr_set_rtcp_fb_ccm(void *sdp_ptr, u16 level, u16 payload_type, u16 inst,
|
|||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
attr_p->attr.rtcp_fb.payload_num = payload_type;
|
||||
attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_CCM;
|
||||
attr_p->attr.rtcp_fb.param.ccm = type;
|
||||
attr_p->attr.rtcp_fb.extra[0] = '\0';
|
||||
return (SDP_SUCCESS);
|
||||
}
|
||||
|
||||
/* Function: sdp_attr_get_extmap_uri
|
||||
* Description: Returns a pointer to the value of the encoding name
|
||||
* parameter specified for the given attribute. Value is
|
||||
* returned as a const ptr and so cannot be modified by the
|
||||
* application. If the given attribute is not defined, NULL
|
||||
* will be returned.
|
||||
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
|
||||
* level The level to check for the attribute.
|
||||
* inst_num The attribute instance number to check.
|
||||
* Returns: Codec value or SDP_CODEC_INVALID.
|
||||
*/
|
||||
const char *sdp_attr_get_extmap_uri(void *sdp_ptr, u16 level,
|
||||
u16 inst_num)
|
||||
{
|
||||
sdp_t *sdp_p = (sdp_t *)sdp_ptr;
|
||||
sdp_attr_t *attr_p;
|
||||
|
||||
if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num);
|
||||
if (attr_p == NULL) {
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
|
||||
CSFLogError(logTag, "%s extmap attribute, level %u instance %u "
|
||||
"not found.", sdp_p->debug_str, level, inst_num);
|
||||
}
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (NULL);
|
||||
} else {
|
||||
return (attr_p->attr.extmap.uri);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function: sdp_attr_get_extmap_id
|
||||
* Description: Returns the id of the extmap specified for the given
|
||||
* attribute. If the given attribute is not defined, 0xFFFF
|
||||
* will be returned.
|
||||
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
|
||||
* level The level to check for the attribute.
|
||||
* inst_num The attribute instance number to check.
|
||||
* Returns: The id of the extmap attribute.
|
||||
*/
|
||||
u16 sdp_attr_get_extmap_id(void *sdp_ptr, u16 level,
|
||||
u16 inst_num)
|
||||
{
|
||||
sdp_t *sdp_p = (sdp_t *)sdp_ptr;
|
||||
sdp_attr_t *attr_p;
|
||||
|
||||
if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num);
|
||||
if (attr_p == NULL) {
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
|
||||
CSFLogError(logTag, "%s extmap attribute, level %u instance %u "
|
||||
"not found.", sdp_p->debug_str, level, inst_num);
|
||||
}
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return 0xFFFF;
|
||||
} else {
|
||||
return (attr_p->attr.extmap.id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function: sdp_attr_set_extmap
|
||||
* Description: Sets the value of an rtcp-fb:...ccm attribute
|
||||
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
|
||||
* level The level to set the attribute.
|
||||
* id The id to set the attribute.
|
||||
* uri The uri to set the attribute.
|
||||
* inst The attribute instance number to check.
|
||||
* Returns: SDP_SUCCESS Attribute param was set successfully.
|
||||
* SDP_INVALID_PARAMETER Specified attribute is not defined.
|
||||
*/
|
||||
sdp_result_e
|
||||
sdp_attr_set_extmap(void *sdp_ptr, u16 level, u16 id, const char* uri, u16 inst)
|
||||
{
|
||||
sdp_t *sdp_p = (sdp_t *)sdp_ptr;
|
||||
sdp_attr_t *attr_p;
|
||||
|
||||
if (!sdp_verify_sdp_ptr(sdp_p)) {
|
||||
return (SDP_INVALID_SDP_PTR);
|
||||
}
|
||||
|
||||
attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst);
|
||||
if (!attr_p) {
|
||||
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
|
||||
CSFLogError(logTag, "%s extmap attribute, level %u "
|
||||
"instance %u not found.", sdp_p->debug_str, level,
|
||||
inst);
|
||||
}
|
||||
sdp_p->conf_p->num_invalid_param++;
|
||||
return (SDP_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
attr_p->attr.extmap.id = id;
|
||||
sstrncpy(attr_p->attr.extmap.uri, uri, SDP_MAX_STRING_LEN+1);
|
||||
return (SDP_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
|
@ -176,8 +176,9 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] =
|
|||
sdp_parse_attr_setup, sdp_build_attr_setup},
|
||||
{"connection", sizeof("connection"),
|
||||
sdp_parse_attr_connection, sdp_build_attr_connection},
|
||||
{"extmap", sizeof("extmap"),
|
||||
sdp_parse_attr_extmap, sdp_build_attr_extmap},
|
||||
};
|
||||
|
||||
/* Note: These *must* be in the same order as the enum types. */
|
||||
const sdp_namearray_t sdp_media[SDP_MAX_MEDIA_TYPES] =
|
||||
{
|
||||
|
|
|
@ -167,11 +167,16 @@ extern sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
|
|||
extern sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
flex_string *fs);
|
||||
extern sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
|
||||
sdp_attr_t *attr_p,
|
||||
flex_string *fs);
|
||||
extern sdp_result_e sdp_parse_attr_mptime(
|
||||
sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_mptime(
|
||||
sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs);
|
||||
|
||||
extern sdp_result_e sdp_parse_attr_x_sidin(
|
||||
sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
|
||||
extern sdp_result_e sdp_build_attr_x_sidin(
|
||||
|
|
|
@ -246,10 +246,10 @@ typedef enum {
|
|||
SDP_ATTR_RTCP_FB, /* RFC 4585 */
|
||||
SDP_ATTR_SETUP,
|
||||
SDP_ATTR_CONNECTION,
|
||||
SDP_ATTR_EXTMAP, /* RFC 5285 */
|
||||
SDP_MAX_ATTR_TYPES,
|
||||
SDP_ATTR_INVALID
|
||||
} sdp_attr_e;
|
||||
|
||||
/* This is here so that it can be used in the VcmSIPCCBinding interface */
|
||||
typedef enum {
|
||||
SDP_SETUP_NOT_FOUND = -1,
|
||||
|
|
|
@ -338,6 +338,8 @@ typedef struct vcm_attrs_t_ {
|
|||
cc_boolean mute;
|
||||
cc_boolean is_video;
|
||||
cc_boolean rtcp_mux;
|
||||
cc_boolean audio_level;
|
||||
uint8_t audio_level_id;
|
||||
vcm_audioAttrs_t audio; /**< audio line attribs */
|
||||
vcm_videoAttrs_t video; /**< Video Atrribs */
|
||||
uint32_t bundle_level; /**< Where bundle transport info lives, if any */
|
||||
|
|
|
@ -191,6 +191,14 @@ class SdpTest : public ::testing::Test {
|
|||
type), SDP_SUCCESS);
|
||||
return inst_num;
|
||||
}
|
||||
u16 AddNewExtMap(int level, const char* uri) {
|
||||
u16 inst_num = 0;
|
||||
EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, level, 0, SDP_ATTR_EXTMAP,
|
||||
&inst_num), SDP_SUCCESS);
|
||||
EXPECT_EQ(sdp_attr_set_extmap(sdp_ptr_, level, inst_num,
|
||||
uri, inst_num), SDP_SUCCESS);
|
||||
return inst_num;
|
||||
}
|
||||
|
||||
u16 AddNewFmtpMaxFs(int level, u32 max_fs) {
|
||||
u16 inst_num = 0;
|
||||
|
@ -725,6 +733,23 @@ TEST_F(SdpTest, parseRtcpFbAllPayloads) {
|
|||
SDP_RTCP_FB_ACK_RPSI);
|
||||
}
|
||||
}
|
||||
TEST_F(SdpTest, addExtMap) {
|
||||
InitLocalSdp();
|
||||
int level = AddNewMedia(SDP_MEDIA_VIDEO);
|
||||
AddNewExtMap(level, SDP_EXTMAP_AUDIO_LEVEL);
|
||||
std::string body = SerializeSdp();
|
||||
ASSERT_NE(body.find("a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(SdpTest, parseExtMap) {
|
||||
ParseSdp(kVideoSdp +
|
||||
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n");
|
||||
ASSERT_STREQ(sdp_attr_get_extmap_uri(sdp_ptr_, 1, 1),
|
||||
SDP_EXTMAP_AUDIO_LEVEL);
|
||||
ASSERT_EQ(sdp_attr_get_extmap_id(sdp_ptr_, 1, 1),
|
||||
1);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(SdpTest, parseFmtpMaxFs) {
|
||||
u32 val = 0;
|
||||
|
@ -732,7 +757,6 @@ TEST_F(SdpTest, parseFmtpMaxFs) {
|
|||
ASSERT_EQ(sdp_attr_get_fmtp_max_fs(sdp_ptr_, 1, 0, 1, &val), SDP_SUCCESS);
|
||||
ASSERT_EQ(val, 300);
|
||||
}
|
||||
|
||||
TEST_F(SdpTest, parseFmtpMaxFr) {
|
||||
u32 val = 0;
|
||||
ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=300;max-fr=30\r\n");
|
||||
|
|
|
@ -275,7 +275,7 @@
|
|||
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
||||
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
||||
<h1 id="et_malformedURI">&malformedURI.title;</h1>
|
||||
<h1 id="et_protocolNotFound">&protocolNotFound.title;</h1>
|
||||
<h1 id="et_unknownProtocolFound">&unknownProtocolFound.title;</h1>
|
||||
<h1 id="et_connectionFailure">&connectionFailure.title;</h1>
|
||||
<h1 id="et_netTimeout">&netTimeout.title;</h1>
|
||||
<h1 id="et_redirectLoop">&redirectLoop.title;</h1>
|
||||
|
@ -304,7 +304,7 @@
|
|||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc2;</div>
|
||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||
<div id="ed_malformedURI">&malformedURI.longDesc;</div>
|
||||
<div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
|
||||
<div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
|
||||
<div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
|
||||
<div id="ed_netTimeout">&netTimeout.longDesc;</div>
|
||||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
malformedURI=The URL is not valid and cannot be loaded.
|
||||
fileNotFound=Firefox can't find the file at %S.
|
||||
dnsNotFound=Firefox can't find the server at %S.
|
||||
protocolNotFound=Firefox doesn't know how to open this address, because the protocol (%S) isn't associated with any program.
|
||||
unknownProtocolFound=Firefox doesn't know how to open this address, because one of the following protocols (%S) isn't associated with any program or is not allowed in this context.
|
||||
connectionFailure=Firefox can't establish a connection to the server at %S.
|
||||
netInterrupt=The connection to %S was interrupted while the page was loading.
|
||||
netTimeout=The server at %S is taking too long to respond.
|
||||
|
|
|
@ -83,8 +83,8 @@
|
|||
<!ENTITY netTimeout.title "The connection has timed out">
|
||||
<!ENTITY netTimeout.longDesc "&sharedLongDesc2;">
|
||||
|
||||
<!ENTITY protocolNotFound.title "The address wasn't understood">
|
||||
<!ENTITY protocolNotFound.longDesc "
|
||||
<!ENTITY unknownProtocolFound.title "The address wasn't understood">
|
||||
<!ENTITY unknownProtocolFound.longDesc "
|
||||
<ul>
|
||||
<li>You might need to install other software to open this address.</li>
|
||||
</ul>
|
||||
|
|
|
@ -616,8 +616,6 @@ pref("print.use_global_printsettings", true);
|
|||
// Save the Printings after each print job
|
||||
pref("print.save_print_settings", true);
|
||||
|
||||
pref("print.whileInPrintPreview", true);
|
||||
|
||||
// Cache old Presentation when going into Print Preview
|
||||
pref("print.always_cache_old_pres", false);
|
||||
|
||||
|
|
|
@ -6938,7 +6938,7 @@ club
|
|||
voting
|
||||
|
||||
// TOKYO : 2013-11-13 GMO Registry, Inc.
|
||||
TOKYO
|
||||
tokyo
|
||||
|
||||
// moe : 2013-11-13 Interlink Co., Ltd.
|
||||
moe
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Test for view source</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
@ -25,38 +24,26 @@
|
|||
return xhr.responseText;
|
||||
}
|
||||
|
||||
// Start a "view source" test using the document at "testUrl". Note that
|
||||
// the test will actually complete asynchronously.
|
||||
function startViewSourceTest(testUrl) {
|
||||
// We will "view" the source of the document in a new window.
|
||||
// If everything is working correctly, the "source" will simply be the
|
||||
// text content of the new window's document's body element.
|
||||
// We have to use a window as view-source: is only allowed in top level,
|
||||
// see bug 624883.
|
||||
|
||||
// We will "view" the source of the document in an IFRAME.
|
||||
// If everything is working correctly, the "source" will simply be the
|
||||
// text content of the IFRAME document's top element.
|
||||
// Open the new window.
|
||||
var windowWithSource = window.open("about:blank");
|
||||
|
||||
// Create the IFRAME.
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = "view-source:" + testUrl;
|
||||
// The actual test will be carried out inside the window's onload handler.
|
||||
windowWithSource.onload = function () {
|
||||
var apparentSource = this.document.body.textContent;
|
||||
var actualSource = fetch(location.href);
|
||||
is(apparentSource, actualSource, "Sources should match");
|
||||
|
||||
// The actual test will be carried out inside the IFRAME's onload handler.
|
||||
iframe.onload = function () {
|
||||
|
||||
var apparentSource = this.contentDocument.body.textContent;
|
||||
var actualSource = fetch(testUrl);
|
||||
|
||||
// OK, verify that the apparent source and the actual source agree.
|
||||
ok(apparentSource == actualSource, "Sources should match");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Our test IFRAME is ready to go. However, it will not load until we
|
||||
// actually append it to the document. Do that now. Note that the test
|
||||
// itself will run asynchronously some time after this function returns.
|
||||
document.body.appendChild(iframe);
|
||||
windowWithSource.close()
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Start a test using this document as the test document.
|
||||
startViewSourceTest(document.location.href);
|
||||
windowWithSource.location.href = "view-source:" + location.href;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -93,6 +93,24 @@ insertErrorIntoVerifyLog(CERTCertificate* cert, const PRErrorCode err,
|
|||
}
|
||||
#endif
|
||||
|
||||
SECStatus chainValidationCallback(void* state, const CERTCertList* certList,
|
||||
PRBool* chainOK)
|
||||
{
|
||||
*chainOK = PR_FALSE;
|
||||
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("verifycert: Inside the Callback \n"));
|
||||
|
||||
// On sanity failure we fail closed.
|
||||
if (!certList) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("verifycert: Short circuit, callback, "
|
||||
"sanity check failed \n"));
|
||||
PR_SetError(PR_INVALID_STATE_ERROR, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
*chainOK = PR_TRUE;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
static SECStatus
|
||||
ClassicVerifyCert(CERTCertificate* cert,
|
||||
const SECCertificateUsage usage,
|
||||
|
@ -300,7 +318,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert,
|
|||
rev.chainTests.number_of_defined_methods = cert_revocation_method_ocsp + 1;
|
||||
|
||||
const bool localOnly = flags & FLAG_LOCAL_ONLY;
|
||||
CERTValInParam cvin[6];
|
||||
CERTValInParam cvin[7];
|
||||
|
||||
// Parameters for both EV and DV validation
|
||||
cvin[0].type = cert_pi_useAIACertFetch;
|
||||
|
@ -310,6 +328,16 @@ CertVerifier::VerifyCert(CERTCertificate* cert,
|
|||
cvin[2].type = cert_pi_date;
|
||||
cvin[2].value.scalar.time = time;
|
||||
i = 3;
|
||||
|
||||
CERTChainVerifyCallback callbackContainer;
|
||||
if (usage == certificateUsageSSLServer) {
|
||||
callbackContainer.isChainValid = chainValidationCallback;
|
||||
callbackContainer.isChainValidArg = nullptr;
|
||||
cvin[i].type = cert_pi_chainVerifyCallback;
|
||||
cvin[i].value.pointer.chainVerifyCallback = &callbackContainer;
|
||||
++i;
|
||||
}
|
||||
|
||||
const size_t evParamLocation = i;
|
||||
|
||||
if (evPolicy != SEC_OID_UNKNOWN) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -160,6 +161,48 @@ SpecialPowersObserverAPI.prototype = {
|
|||
return Services.io.newURI(url, null, null);
|
||||
},
|
||||
|
||||
_readUrlAsString: function(aUrl) {
|
||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
||||
// to evaluate http:// urls...
|
||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
var channel = Services.io.newChannel(aUrl, null, null);
|
||||
var input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
var str;
|
||||
var buffer = [];
|
||||
|
||||
while ((str = scriptableStream.read(4096))) {
|
||||
buffer.push(str);
|
||||
}
|
||||
|
||||
var output = buffer.join("");
|
||||
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
|
||||
var status;
|
||||
try {
|
||||
channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
status = channel.responseStatus;
|
||||
} catch(e) {
|
||||
/* The channel is not a nsIHttpCHannel, but that's fine */
|
||||
dump("-*- _readUrlAsString: Got an error while fetching " +
|
||||
"chrome script '" + aUrl + "': (" + e.name + ") " + e.message + ". " +
|
||||
"Ignoring.\n");
|
||||
}
|
||||
|
||||
if (status == 404) {
|
||||
throw new SpecialPowersException(
|
||||
"Error while executing chrome script '" + aUrl + "':\n" +
|
||||
"The script doesn't exists. Ensure you have registered it in " +
|
||||
"'support-files' in your mochitest.ini.");
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
/**
|
||||
* messageManager callback function
|
||||
* This will get requests from our API in the window and process them in chrome for it
|
||||
|
@ -300,16 +343,7 @@ SpecialPowersObserverAPI.prototype = {
|
|||
var url = aMessage.json.url;
|
||||
var id = aMessage.json.id;
|
||||
|
||||
// Fetch script content as we can't use scriptloader's loadSubScript
|
||||
// to evaluate http:// urls...
|
||||
var scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
var channel = Services.io.newChannel(url, null, null);
|
||||
var input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
var jsScript = scriptableStream.read(input.available());
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
var jsScript = this._readUrlAsString(url);
|
||||
|
||||
// Setup a chrome sandbox that has access to sendAsyncMessage
|
||||
// and addMessageListener in order to communicate with
|
||||
|
@ -332,7 +366,8 @@ SpecialPowersObserverAPI.prototype = {
|
|||
Components.utils.evalInSandbox(jsScript, sb, "1.8", url, 1);
|
||||
} catch(e) {
|
||||
throw new SpecialPowersException("Error while executing chrome " +
|
||||
"script '" + url + "':\n" + e);
|
||||
"script '" + url + "':\n" + e + "\n" +
|
||||
e.fileName + ":" + e.lineNumber);
|
||||
}
|
||||
return undefined; // See comment at the beginning of this function.
|
||||
|
||||
|
|
|
@ -9,14 +9,24 @@ const Cc = Components.classes;
|
|||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Sqlite.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesBackups",
|
||||
"resource://gre/modules/PlacesBackups.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Deprecated",
|
||||
"resource://gre/modules/Deprecated.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => new TextDecoder());
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextEncoder", () => new TextEncoder());
|
||||
XPCOMUtils.defineLazyGetter(this, "localFileCtor",
|
||||
() => Components.Constructor("@mozilla.org/file/local;1",
|
||||
"nsILocalFile", "initWithPath"));
|
||||
|
||||
this.BookmarkJSONUtils = Object.freeze({
|
||||
/**
|
||||
|
@ -41,8 +51,8 @@ this.BookmarkJSONUtils = Object.freeze({
|
|||
* @note any item annotated with "places/excludeFromBackup" won't be removed
|
||||
* before executing the restore.
|
||||
*
|
||||
* @param aFile
|
||||
* nsIFile of bookmarks in JSON format to be restored.
|
||||
* @param aFilePath
|
||||
* OS.File path or nsIFile of bookmarks in JSON format to be restored.
|
||||
* @param aReplace
|
||||
* Boolean if true, replace existing bookmarks, else merge.
|
||||
*
|
||||
|
@ -50,24 +60,51 @@ this.BookmarkJSONUtils = Object.freeze({
|
|||
* @resolves When the new bookmarks have been created.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
importFromFile: function BJU_importFromFile(aFile, aReplace) {
|
||||
importFromFile: function BJU_importFromFile(aFilePath, aReplace) {
|
||||
let importer = new BookmarkImporter();
|
||||
return importer.importFromFile(aFile, aReplace);
|
||||
// TODO (bug 967192): convert to pure OS.File
|
||||
let file = aFilePath instanceof Ci.nsIFile ? aFilePath
|
||||
: new localFileCtor(aFilePath);
|
||||
return importer.importFromFile(file, aReplace);
|
||||
},
|
||||
|
||||
/**
|
||||
* Serializes bookmarks using JSON, and writes to the supplied file.
|
||||
* Serializes bookmarks using JSON, and writes to the supplied file path.
|
||||
*
|
||||
* @param aLocalFile
|
||||
* nsIFile for the "bookmarks.json" file to be created.
|
||||
* @param aFilePath
|
||||
* OS.File path for the "bookmarks.json" file to be created.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the file has been created.
|
||||
* @resolves To the exported bookmarks count when the file has been created.
|
||||
* @rejects JavaScript exception.
|
||||
* @deprecated passing an nsIFile is deprecated
|
||||
*/
|
||||
exportToFile: function BJU_exportToFile(aLocalFile) {
|
||||
let exporter = new BookmarkExporter();
|
||||
return exporter.exportToFile(aLocalFile);
|
||||
exportToFile: function BJU_exportToFile(aFilePath) {
|
||||
if (aFilePath instanceof Ci.nsIFile) {
|
||||
Deprecated.warning("Passing an nsIFile to BookmarksJSONUtils.exportToFile " +
|
||||
"is deprecated. Please use an OS.File path instead.",
|
||||
"https://developer.mozilla.org/docs/JavaScript_OS.File");
|
||||
aFilePath = aFilePath.path;
|
||||
}
|
||||
return Task.spawn(function* () {
|
||||
let [bookmarks, count] = yield PlacesBackups.getBookmarksTree();
|
||||
let startTime = Date.now();
|
||||
let jsonString = JSON.stringify(bookmarks);
|
||||
// Report the time taken to convert the tree to JSON.
|
||||
try {
|
||||
Services.telemetry
|
||||
.getHistogramById("PLACES_BACKUPS_TOJSON_MS")
|
||||
.add(Date.now() - startTime);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to report telemetry.");
|
||||
}
|
||||
|
||||
// Write to the temp folder first, to avoid leaving back partial files.
|
||||
let tmpPath = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
OS.Path.basename(aFilePath) + ".tmp");
|
||||
yield OS.File.writeAtomic(aFilePath, jsonString, { tmpPath: tmpPath });
|
||||
return count;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -362,7 +399,8 @@ BookmarkImporter.prototype = {
|
|||
});
|
||||
return [folderIdMap, searchIds];
|
||||
}
|
||||
} else if (aData.livemark && aData.annos) {
|
||||
} else if (aData.annos &&
|
||||
aData.annos.some(anno => anno.name == PlacesUtils.LMANNO_FEEDURI)) {
|
||||
// Node is a livemark
|
||||
let feedURI = null;
|
||||
let siteURI = null;
|
||||
|
@ -422,7 +460,8 @@ BookmarkImporter.prototype = {
|
|||
if (aData.keyword)
|
||||
PlacesUtils.bookmarks.setKeywordForBookmark(id, aData.keyword);
|
||||
if (aData.tags) {
|
||||
let tags = aData.tags.split(", ");
|
||||
// TODO (bug 967196) the tagging service should trim by itself.
|
||||
let tags = aData.tags.split(",").map(tag => tag.trim());
|
||||
if (tags.length)
|
||||
PlacesUtils.tagging.tagURI(NetUtil.newURI(aData.uri), tags);
|
||||
}
|
||||
|
@ -502,306 +541,6 @@ function fixupQuery(aQueryURI, aFolderIdMap) {
|
|||
return NetUtil.newURI(stringURI);
|
||||
}
|
||||
|
||||
function BookmarkExporter() {}
|
||||
BookmarkExporter.prototype = {
|
||||
exportToFile: function BE_exportToFile(aLocalFile) {
|
||||
return Task.spawn(this._writeToFile(aLocalFile));
|
||||
},
|
||||
|
||||
_converterOut: null,
|
||||
|
||||
_writeToFile: function BE__writeToFile(aLocalFile) {
|
||||
// Create a file that can be accessed by the current user only.
|
||||
let safeFileOut = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
safeFileOut.init(aLocalFile, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
|
||||
FileUtils.MODE_TRUNCATE, parseInt("0600", 8), 0);
|
||||
let nodeCount;
|
||||
|
||||
try {
|
||||
// We need a buffered output stream for performance. See bug 202477.
|
||||
let bufferedOut = Cc["@mozilla.org/network/buffered-output-stream;1"].
|
||||
createInstance(Ci.nsIBufferedOutputStream);
|
||||
bufferedOut.init(safeFileOut, 4096);
|
||||
try {
|
||||
// Write bookmarks in UTF-8.
|
||||
this._converterOut = Cc["@mozilla.org/intl/converter-output-stream;1"].
|
||||
createInstance(Ci.nsIConverterOutputStream);
|
||||
this._converterOut.init(bufferedOut, "utf-8", 0, 0);
|
||||
try {
|
||||
nodeCount = yield this._writeContentToFile();
|
||||
|
||||
// Flush the buffer and retain the target file on success only.
|
||||
bufferedOut.QueryInterface(Ci.nsISafeOutputStream).finish();
|
||||
} finally {
|
||||
this._converterOut.close();
|
||||
this._converterOut = null;
|
||||
}
|
||||
} finally {
|
||||
bufferedOut.close();
|
||||
}
|
||||
} finally {
|
||||
safeFileOut.close();
|
||||
}
|
||||
throw new Task.Result(nodeCount);
|
||||
},
|
||||
|
||||
_writeContentToFile: function BE__writeContentToFile() {
|
||||
return Task.spawn(function() {
|
||||
// Weep over stream interface variance.
|
||||
let streamProxy = {
|
||||
converter: this._converterOut,
|
||||
write: function(aData, aLen) {
|
||||
this.converter.writeString(aData);
|
||||
}
|
||||
};
|
||||
|
||||
// Get list of itemIds that must be excluded from the backup.
|
||||
let excludeItems = PlacesUtils.annotations.getItemsWithAnnotation(
|
||||
PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO);
|
||||
// Serialize to JSON and write to stream.
|
||||
let nodeCount = yield BookmarkRow.serializeJSONToOutputStream(streamProxy,
|
||||
excludeItems);
|
||||
throw new Task.Result(nodeCount);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
let BookmarkRow = {
|
||||
/**
|
||||
* Serializes the SQL results as JSON with async SQL call and writes the
|
||||
* serialization to the given output stream.
|
||||
*
|
||||
* @param aStream
|
||||
* An nsIOutputStream. NOTE: it only uses the write(str, len)
|
||||
* method of nsIOutputStream. The caller is responsible for
|
||||
* closing the stream.
|
||||
* @param aExcludeItems
|
||||
* An array of item ids that should not be written to the backup.
|
||||
* @return {Promise}
|
||||
* @resolves the number of serialized uri nodes.
|
||||
*/
|
||||
serializeJSONToOutputStream: function(aStream, aExcludeItems) {
|
||||
return Task.spawn(function() {
|
||||
let nodes = [];
|
||||
let nodeCount = 0;
|
||||
|
||||
let dbFilePath = OS.Path.join(OS.Constants.Path.profileDir,
|
||||
"places.sqlite");
|
||||
let conn = yield Sqlite.openConnection({ path: dbFilePath,
|
||||
sharedMemoryCache: false });
|
||||
try {
|
||||
let rows = yield conn.execute(
|
||||
"SELECT b.id, h.url, b.position, b.title, b.parent, " +
|
||||
"b.type, b.dateAdded, b.lastModified, b.guid, t.parent AS grandParent " +
|
||||
"FROM moz_bookmarks b " +
|
||||
"LEFT JOIN moz_bookmarks t ON t.id = b.parent " +
|
||||
"LEFT JOIN moz_places h ON h.id = b.fk " +
|
||||
"ORDER BY b.parent, b.position, b.id");
|
||||
|
||||
// Create a Map for lookup.
|
||||
let rowMap = new Map();
|
||||
for (let row of rows) {
|
||||
let parent = row.getResultByName("parent");
|
||||
if (rowMap.has(parent)) {
|
||||
let data = rowMap.get(parent);
|
||||
data.children.push(row);
|
||||
} else {
|
||||
rowMap.set(parent, { children: [row] });
|
||||
}
|
||||
}
|
||||
|
||||
let root = rowMap.get(0);
|
||||
if (!root) {
|
||||
throw new Error("Root does not exist.");
|
||||
}
|
||||
let result = yield BookmarkRow._appendConvertedNode(root.children[0],
|
||||
rowMap,
|
||||
nodes,
|
||||
aExcludeItems);
|
||||
if (result.appendedNode) {
|
||||
nodeCount = result.nodeCount;
|
||||
let json = JSON.stringify(nodes[0]);
|
||||
aStream.write(json, json.length);
|
||||
}
|
||||
} catch(e) {
|
||||
Cu.reportError("serializeJSONToOutputStream error " + e);
|
||||
} finally {
|
||||
yield conn.close();
|
||||
}
|
||||
throw new Task.Result(nodeCount);
|
||||
});
|
||||
},
|
||||
|
||||
_appendConvertedNode: function BR__appendConvertedNode(
|
||||
aRow, aRowMap, aNodes, aExcludeItems) {
|
||||
return Task.spawn(function() {
|
||||
let node = {};
|
||||
let nodeCount = 0;
|
||||
|
||||
this._addGenericProperties(aRow, node);
|
||||
|
||||
let parent = aRow.getResultByName("parent");
|
||||
let grandParent = parent ? aRow.getResultByName("grandParent") : null;
|
||||
let type = aRow.getResultByName("type");
|
||||
|
||||
if (type == Ci.nsINavBookmarksService.TYPE_BOOKMARK) {
|
||||
// Tag root accept only folder nodes
|
||||
if (parent == PlacesUtils.tagsFolderId)
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
|
||||
// Check for url validity, since we can't halt while writing a backup.
|
||||
// This will throw if we try to serialize an invalid url and it does
|
||||
// not make sense saving a wrong or corrupt uri node.
|
||||
try {
|
||||
NetUtil.newURI(aRow.getResultByName("url"));
|
||||
} catch (ex) {
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
}
|
||||
yield this._addURIProperties(aRow, node);
|
||||
nodeCount++;
|
||||
} else if (type == Ci.nsINavBookmarksService.TYPE_FOLDER) {
|
||||
// Tag containers accept only uri nodes
|
||||
if (grandParent && grandParent == PlacesUtils.tagsFolderId) {
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
}
|
||||
this._addContainerProperties(aRow, node);
|
||||
} else if (type == Ci.nsINavBookmarksService.TYPE_SEPARATOR) {
|
||||
// Tag root accept only folder nodes
|
||||
// Tag containers accept only uri nodes
|
||||
if ((parent == PlacesUtils.tagsFolderId) ||
|
||||
(grandParent == PlacesUtils.tagsFolderId)) {
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
}
|
||||
this._addSeparatorProperties(aRow, node);
|
||||
}
|
||||
|
||||
if (node.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER) {
|
||||
nodeCount += yield this._appendConvertedComplexNode(node,
|
||||
aNodes,
|
||||
aRowMap,
|
||||
aExcludeItems);
|
||||
throw new Task.Result({ appendedNode: true, nodeCount: nodeCount });
|
||||
}
|
||||
|
||||
aNodes.push(node);
|
||||
throw new Task.Result({ appendedNode: true, nodeCount: nodeCount });
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_addGenericProperties: function BR__addGenericProperties(aRow, aJSNode) {
|
||||
let title = aRow.getResultByName("title")
|
||||
aJSNode.title = title ? title : "";
|
||||
aJSNode.guid = aRow.getResultByName("guid");
|
||||
aJSNode.id = aRow.getResultByName("id");
|
||||
aJSNode.index = aRow.getResultByName("position");
|
||||
if (aJSNode.id != -1) {
|
||||
let parent = aRow.getResultByName("parent");
|
||||
if (parent)
|
||||
aJSNode.parent = parent;
|
||||
let dateAdded = aRow.getResultByName("dateAdded");;
|
||||
if (dateAdded)
|
||||
aJSNode.dateAdded = dateAdded;
|
||||
let lastModified = aRow.getResultByName("lastModified");
|
||||
if (lastModified)
|
||||
aJSNode.lastModified = lastModified;
|
||||
|
||||
// XXX need a hasAnnos api
|
||||
let annos = [];
|
||||
try {
|
||||
annos =
|
||||
PlacesUtils.getAnnotationsForItem(aJSNode.id).filter(function(anno) {
|
||||
// XXX should whitelist this instead, w/ a pref for
|
||||
// backup/restore of non-whitelisted annos
|
||||
// XXX causes JSON encoding errors, so utf-8 encode
|
||||
// anno.value = unescape(encodeURIComponent(anno.value));
|
||||
if (anno.name == PlacesUtils.LMANNO_FEEDURI)
|
||||
aJSNode.livemark = 1;
|
||||
return true;
|
||||
});
|
||||
} catch(ex) {}
|
||||
if (annos.length != 0)
|
||||
aJSNode.annos = annos;
|
||||
}
|
||||
// XXXdietrich - store annos for non-bookmark items
|
||||
},
|
||||
|
||||
_addURIProperties: function BR__addURIProperties(aRow, aJSNode) {
|
||||
return Task.spawn(function() {
|
||||
aJSNode.type = PlacesUtils.TYPE_X_MOZ_PLACE;
|
||||
aJSNode.uri = aRow.getResultByName("url");
|
||||
if (aJSNode.id && aJSNode.id != -1) {
|
||||
// Harvest bookmark-specific properties
|
||||
let keyword = PlacesUtils.bookmarks.getKeywordForBookmark(aJSNode.id);
|
||||
if (keyword)
|
||||
aJSNode.keyword = keyword;
|
||||
}
|
||||
|
||||
// Last character-set
|
||||
let uri = NetUtil.newURI(aRow.getResultByName("url"));
|
||||
let lastCharset = yield PlacesUtils.getCharsetForURI(uri)
|
||||
if (lastCharset)
|
||||
aJSNode.charset = lastCharset;
|
||||
});
|
||||
},
|
||||
|
||||
_addSeparatorProperties: function BR__addSeparatorProperties(aRow, aJSNode) {
|
||||
aJSNode.type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR;
|
||||
},
|
||||
|
||||
_addContainerProperties: function BR__addContainerProperties(aRow, aJSNode) {
|
||||
// This is a bookmark or a tag container.
|
||||
// Bookmark folder or a shortcut we should convert to folder.
|
||||
aJSNode.type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER;
|
||||
|
||||
// Mark root folders
|
||||
let itemId = aRow.getResultByName("id");
|
||||
if (itemId == PlacesUtils.placesRootId)
|
||||
aJSNode.root = "placesRoot";
|
||||
else if (itemId == PlacesUtils.bookmarksMenuFolderId)
|
||||
aJSNode.root = "bookmarksMenuFolder";
|
||||
else if (itemId == PlacesUtils.tagsFolderId)
|
||||
aJSNode.root = "tagsFolder";
|
||||
else if (itemId == PlacesUtils.unfiledBookmarksFolderId)
|
||||
aJSNode.root = "unfiledBookmarksFolder";
|
||||
else if (itemId == PlacesUtils.toolbarFolderId)
|
||||
aJSNode.root = "toolbarFolder";
|
||||
},
|
||||
|
||||
_appendConvertedComplexNode: function BR__appendConvertedComplexNode(
|
||||
aNode, aNodes, aRowMap, aExcludeItems) {
|
||||
return Task.spawn(function() {
|
||||
let repr = {};
|
||||
let nodeCount = 0;
|
||||
|
||||
for (let [name, value] in Iterator(aNode))
|
||||
repr[name] = value;
|
||||
repr.children = [];
|
||||
|
||||
let data = aRowMap.get(aNode.id);
|
||||
if (data) {
|
||||
for (let row of data.children) {
|
||||
let id = row.getResultByName("id");
|
||||
// ignore exclude items
|
||||
if (aExcludeItems && aExcludeItems.indexOf(id) != -1) {
|
||||
continue;
|
||||
}
|
||||
let result = yield this._appendConvertedNode(row,
|
||||
aRowMap,
|
||||
repr.children,
|
||||
aExcludeItems);
|
||||
nodeCount += result.nodeCount;
|
||||
}
|
||||
} else {
|
||||
Cu.reportError("_appendConvertedComplexNode error: Unable to find node");
|
||||
}
|
||||
|
||||
aNodes.push(repr);
|
||||
throw new Task.Result(nodeCount);
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
let BookmarkNode = {
|
||||
/**
|
||||
* Serializes the given node (and all its descendents) as JSON
|
||||
|
@ -826,7 +565,7 @@ let BookmarkNode = {
|
|||
serializeAsJSONToOutputStream: function BN_serializeAsJSONToOutputStream(
|
||||
aNode, aStream, aIsUICommand, aResolveShortcuts, aExcludeItems) {
|
||||
|
||||
return Task.spawn(function() {
|
||||
return Task.spawn(function* () {
|
||||
// Serialize to stream
|
||||
let array = [];
|
||||
let result = yield this._appendConvertedNode(aNode, null, array,
|
||||
|
@ -834,18 +573,18 @@ let BookmarkNode = {
|
|||
aResolveShortcuts,
|
||||
aExcludeItems);
|
||||
if (result.appendedNode) {
|
||||
let json = JSON.stringify(array[0]);
|
||||
aStream.write(json, json.length);
|
||||
let jsonString = JSON.stringify(array[0]);
|
||||
aStream.write(jsonString, jsonString.length);
|
||||
} else {
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
throw new Task.Result(result.nodeCount);
|
||||
return result.nodeCount;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_appendConvertedNode: function BN__appendConvertedNode(
|
||||
bNode, aIndex, aArray, aIsUICommand, aResolveShortcuts, aExcludeItems) {
|
||||
return Task.spawn(function() {
|
||||
return Task.spawn(function* () {
|
||||
let node = {};
|
||||
let nodeCount = 0;
|
||||
|
||||
|
@ -863,7 +602,7 @@ let BookmarkNode = {
|
|||
if (PlacesUtils.nodeIsURI(bNode)) {
|
||||
// Tag root accept only folder nodes
|
||||
if (parent && parent.itemId == PlacesUtils.tagsFolderId)
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
return { appendedNode: false, nodeCount: nodeCount };
|
||||
|
||||
// Check for url validity, since we can't halt while writing a backup.
|
||||
// This will throw if we try to serialize an invalid url and it does
|
||||
|
@ -871,7 +610,7 @@ let BookmarkNode = {
|
|||
try {
|
||||
NetUtil.newURI(bNode.uri);
|
||||
} catch (ex) {
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
return { appendedNode: false, nodeCount: nodeCount };
|
||||
}
|
||||
|
||||
yield this._addURIProperties(bNode, node, aIsUICommand);
|
||||
|
@ -879,7 +618,7 @@ let BookmarkNode = {
|
|||
} else if (PlacesUtils.nodeIsContainer(bNode)) {
|
||||
// Tag containers accept only uri nodes
|
||||
if (grandParent && grandParent.itemId == PlacesUtils.tagsFolderId)
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
return { appendedNode: false, nodeCount: nodeCount };
|
||||
|
||||
this._addContainerProperties(bNode, node, aIsUICommand,
|
||||
aResolveShortcuts);
|
||||
|
@ -888,7 +627,7 @@ let BookmarkNode = {
|
|||
// Tag containers accept only uri nodes
|
||||
if ((parent && parent.itemId == PlacesUtils.tagsFolderId) ||
|
||||
(grandParent && grandParent.itemId == PlacesUtils.tagsFolderId))
|
||||
throw new Task.Result({ appendedNode: false, nodeCount: nodeCount });
|
||||
return { appendedNode: false, nodeCount: nodeCount };
|
||||
|
||||
this._addSeparatorProperties(bNode, node);
|
||||
}
|
||||
|
@ -900,11 +639,11 @@ let BookmarkNode = {
|
|||
aIsUICommand,
|
||||
aResolveShortcuts,
|
||||
aExcludeItems)
|
||||
throw new Task.Result({ appendedNode: true, nodeCount: nodeCount });
|
||||
return { appendedNode: true, nodeCount: nodeCount };
|
||||
}
|
||||
|
||||
aArray.push(node);
|
||||
throw new Task.Result({ appendedNode: true, nodeCount: nodeCount });
|
||||
return { appendedNode: true, nodeCount: nodeCount };
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -932,8 +671,6 @@ let BookmarkNode = {
|
|||
// backup/restore of non-whitelisted annos
|
||||
// XXX causes JSON encoding errors, so utf-8 encode
|
||||
// anno.value = unescape(encodeURIComponent(anno.value));
|
||||
if (anno.name == PlacesUtils.LMANNO_FEEDURI)
|
||||
aJSNode.livemark = 1;
|
||||
if (anno.name == PlacesUtils.READ_ONLY_ANNO && aResolveShortcuts) {
|
||||
// When copying a read-only node, remove the read-only annotation.
|
||||
return false;
|
||||
|
@ -1014,7 +751,7 @@ let BookmarkNode = {
|
|||
_appendConvertedComplexNode: function BN__appendConvertedComplexNode(
|
||||
aNode, aSourceNode, aArray, aIsUICommand, aResolveShortcuts,
|
||||
aExcludeItems) {
|
||||
return Task.spawn(function() {
|
||||
return Task.spawn(function* () {
|
||||
let repr = {};
|
||||
let nodeCount = 0;
|
||||
|
||||
|
@ -1023,7 +760,8 @@ let BookmarkNode = {
|
|||
|
||||
// Write child nodes
|
||||
let children = repr.children = [];
|
||||
if (!aNode.livemark) {
|
||||
if (!aNode.annos ||
|
||||
!aNode.annos.some(anno => anno.name == PlacesUtils.LMANNO_FEEDURI)) {
|
||||
PlacesUtils.asContainer(aSourceNode);
|
||||
let wasOpen = aSourceNode.containerOpen;
|
||||
if (!wasOpen)
|
||||
|
@ -1043,7 +781,7 @@ let BookmarkNode = {
|
|||
}
|
||||
|
||||
aArray.push(repr);
|
||||
throw new Task.Result(nodeCount);
|
||||
return nodeCount;
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
|
@ -17,11 +17,16 @@ Cu.import("resource://gre/modules/BookmarkJSONUtils.jsm");
|
|||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
|
||||
"resource://gre/modules/Sqlite.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "localFileCtor",
|
||||
() => Components.Constructor("@mozilla.org/file/local;1",
|
||||
"nsILocalFile", "initWithPath"));
|
||||
|
||||
this.PlacesBackups = {
|
||||
get _filenamesRegex() {
|
||||
|
@ -40,7 +45,14 @@ this.PlacesBackups = {
|
|||
Deprecated.warning(
|
||||
"PlacesBackups.folder is deprecated and will be removed in a future version",
|
||||
"https://bugzilla.mozilla.org/show_bug.cgi?id=859695");
|
||||
return this._folder;
|
||||
},
|
||||
|
||||
/**
|
||||
* This exists just to avoid spamming deprecate warnings from internal calls
|
||||
* needed to support deprecated methods themselves.
|
||||
*/
|
||||
get _folder() {
|
||||
let bookmarksBackupDir = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
|
||||
bookmarksBackupDir.append(this.profileRelativeFolderPath);
|
||||
if (!bookmarksBackupDir.exists()) {
|
||||
|
@ -48,8 +60,8 @@ this.PlacesBackups = {
|
|||
if (!bookmarksBackupDir.exists())
|
||||
throw("Unable to create bookmarks backup folder");
|
||||
}
|
||||
delete this.folder;
|
||||
return this.folder = bookmarksBackupDir;
|
||||
delete this._folder;
|
||||
return this._folder = bookmarksBackupDir;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -58,21 +70,15 @@ this.PlacesBackups = {
|
|||
* @resolve the folder (the folder string path).
|
||||
*/
|
||||
getBackupFolder: function PB_getBackupFolder() {
|
||||
return Task.spawn(function() {
|
||||
if (this._folder) {
|
||||
throw new Task.Result(this._folder);
|
||||
return Task.spawn(function* () {
|
||||
if (this._backupFolder) {
|
||||
return this._backupFolder;
|
||||
}
|
||||
let profileDir = OS.Constants.Path.profileDir;
|
||||
let backupsDirPath = OS.Path.join(profileDir, this.profileRelativeFolderPath);
|
||||
yield OS.File.makeDir(backupsDirPath, { ignoreExisting: true }).then(
|
||||
function onSuccess() {
|
||||
this._folder = backupsDirPath;
|
||||
}.bind(this),
|
||||
function onError() {
|
||||
throw("Unable to create bookmarks backup folder");
|
||||
});
|
||||
throw new Task.Result(this._folder);
|
||||
}.bind(this));
|
||||
yield OS.File.makeDir(backupsDirPath, { ignoreExisting: true });
|
||||
return this._backupFolder = backupsDirPath;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
get profileRelativeFolderPath() "bookmarkbackups",
|
||||
|
@ -84,10 +90,17 @@ this.PlacesBackups = {
|
|||
Deprecated.warning(
|
||||
"PlacesBackups.entries is deprecated and will be removed in a future version",
|
||||
"https://bugzilla.mozilla.org/show_bug.cgi?id=859695");
|
||||
return this._entries;
|
||||
},
|
||||
|
||||
delete this.entries;
|
||||
this.entries = [];
|
||||
let files = this.folder.directoryEntries;
|
||||
/**
|
||||
* This exists just to avoid spamming deprecate warnings from internal calls
|
||||
* needed to support deprecated methods themselves.
|
||||
*/
|
||||
get _entries() {
|
||||
delete this._entries;
|
||||
this._entries = [];
|
||||
let files = this._folder.directoryEntries;
|
||||
while (files.hasMoreElements()) {
|
||||
let entry = files.getNext().QueryInterface(Ci.nsIFile);
|
||||
// A valid backup is any file that matches either the localized or
|
||||
|
@ -99,15 +112,15 @@ this.PlacesBackups = {
|
|||
entry.remove(false);
|
||||
continue;
|
||||
}
|
||||
this.entries.push(entry);
|
||||
this._entries.push(entry);
|
||||
}
|
||||
}
|
||||
this.entries.sort((a, b) => {
|
||||
this._entries.sort((a, b) => {
|
||||
let aDate = this.getDateForFile(a);
|
||||
let bDate = this.getDateForFile(b);
|
||||
return aDate < bDate ? 1 : aDate > bDate ? -1 : 0;
|
||||
});
|
||||
return this.entries;
|
||||
return this._entries;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -116,10 +129,10 @@ this.PlacesBackups = {
|
|||
* @resolve a sorted array of string paths.
|
||||
*/
|
||||
getBackupFiles: function PB_getBackupFiles() {
|
||||
return Task.spawn(function() {
|
||||
if (this._backupFiles) {
|
||||
throw new Task.Result(this._backupFiles);
|
||||
}
|
||||
return Task.spawn(function* () {
|
||||
if (this._backupFiles)
|
||||
return this._backupFiles;
|
||||
|
||||
this._backupFiles = [];
|
||||
|
||||
let backupFolderPath = yield this.getBackupFolder();
|
||||
|
@ -138,13 +151,13 @@ this.PlacesBackups = {
|
|||
}.bind(this));
|
||||
iterator.close();
|
||||
|
||||
this._backupFiles.sort(function(a, b) {
|
||||
this._backupFiles.sort((a, b) => {
|
||||
let aDate = this.getDateForFile(a);
|
||||
let bDate = this.getDateForFile(b);
|
||||
return aDate < bDate ? 1 : aDate > bDate ? -1 : 0;
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
throw new Task.Result(this._backupFiles);
|
||||
return this._backupFiles;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -194,10 +207,10 @@ this.PlacesBackups = {
|
|||
"https://bugzilla.mozilla.org/show_bug.cgi?id=859695");
|
||||
|
||||
let fileExt = aFileExt || "(json|html)";
|
||||
for (let i = 0; i < this.entries.length; i++) {
|
||||
for (let i = 0; i < this._entries.length; i++) {
|
||||
let rx = new RegExp("\." + fileExt + "$");
|
||||
if (this.entries[i].leafName.match(rx))
|
||||
return this.entries[i];
|
||||
if (this._entries[i].leafName.match(rx))
|
||||
return this._entries[i];
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
@ -212,16 +225,16 @@ this.PlacesBackups = {
|
|||
* @result the path to the file.
|
||||
*/
|
||||
getMostRecentBackup: function PB_getMostRecentBackup(aFileExt) {
|
||||
return Task.spawn(function() {
|
||||
return Task.spawn(function* () {
|
||||
let fileExt = aFileExt || "(json|html)";
|
||||
let entries = yield this.getBackupFiles();
|
||||
for (let entry of entries) {
|
||||
let rx = new RegExp("\." + fileExt + "$");
|
||||
if (OS.Path.basename(entry).match(rx)) {
|
||||
throw new Task.Result(entry);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
throw new Task.Result(null);
|
||||
return null;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -230,23 +243,31 @@ this.PlacesBackups = {
|
|||
* Note: any item that should not be backed up must be annotated with
|
||||
* "places/excludeFromBackup".
|
||||
*
|
||||
* @param aFile
|
||||
* nsIFile where to save JSON backup.
|
||||
* @param aFilePath
|
||||
* OS.File path for the "bookmarks.json" file to be created.
|
||||
* @return {Promise}
|
||||
* @resolves the number of serialized uri nodes.
|
||||
* @deprecated passing an nsIFile is deprecated
|
||||
*/
|
||||
saveBookmarksToJSONFile: function PB_saveBookmarksToJSONFile(aFile) {
|
||||
return Task.spawn(function() {
|
||||
let nodeCount = yield BookmarkJSONUtils.exportToFile(aFile);
|
||||
saveBookmarksToJSONFile: function PB_saveBookmarksToJSONFile(aFilePath) {
|
||||
if (aFilePath instanceof Ci.nsIFile) {
|
||||
Deprecated.warning("Passing an nsIFile to PlacesBackups.saveBookmarksToJSONFile " +
|
||||
"is deprecated. Please use an OS.File path instead.",
|
||||
"https://developer.mozilla.org/docs/JavaScript_OS.File");
|
||||
aFilePath = aFilePath.path;
|
||||
}
|
||||
return Task.spawn(function* () {
|
||||
let nodeCount = yield BookmarkJSONUtils.exportToFile(aFilePath);
|
||||
|
||||
let backupFolderPath = yield this.getBackupFolder();
|
||||
if (aFile.parent.path == backupFolderPath) {
|
||||
// Update internal cache.
|
||||
this.entries.push(aFile);
|
||||
if (OS.Path.dirname(aFilePath) == backupFolderPath) {
|
||||
// We are creating a backup in the default backups folder,
|
||||
// so just update the internal cache.
|
||||
this._entries.unshift(new localFileCtor(aFilePath));
|
||||
if (!this._backupFiles) {
|
||||
yield this.getBackupFiles();
|
||||
}
|
||||
this._backupFiles.push(aFile.path);
|
||||
this._backupFiles.unshift(aFilePath);
|
||||
} else {
|
||||
// If we are saving to a folder different than our backups folder, then
|
||||
// we also want to copy this new backup to it.
|
||||
|
@ -257,24 +278,20 @@ this.PlacesBackups = {
|
|||
{ nodeCount: nodeCount });
|
||||
let newFilePath = OS.Path.join(backupFolderPath, newFilename);
|
||||
let backupFile = yield this._getBackupFileForSameDate(name);
|
||||
|
||||
if (backupFile) {
|
||||
yield OS.File.remove(backupFile, { ignoreAbsent: true });
|
||||
} else {
|
||||
let file = new FileUtils.File(newFilePath);
|
||||
|
||||
if (!backupFile) {
|
||||
// Update internal cache if we are not replacing an existing
|
||||
// backup file.
|
||||
this.entries.push(file);
|
||||
this._entries.unshift(new localFileCtor(newFilePath));
|
||||
if (!this._backupFiles) {
|
||||
yield this.getBackupFiles();
|
||||
}
|
||||
this._backupFiles.push(file.path);
|
||||
this._backupFiles.unshift(newFilePath);
|
||||
}
|
||||
yield OS.File.copy(aFile.path, newFilePath);
|
||||
|
||||
yield OS.File.copy(aFilePath, newFilePath);
|
||||
}
|
||||
|
||||
throw new Task.Result(nodeCount);
|
||||
return nodeCount;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -292,7 +309,7 @@ this.PlacesBackups = {
|
|||
* @return {Promise}
|
||||
*/
|
||||
create: function PB_create(aMaxBackups, aForceBackup) {
|
||||
return Task.spawn(function() {
|
||||
return Task.spawn(function* () {
|
||||
// Construct the new leafname.
|
||||
let newBackupFilename = this.getFilenameForDate();
|
||||
let mostRecentBackupFile = yield this.getMostRecentBackup();
|
||||
|
@ -314,7 +331,7 @@ this.PlacesBackups = {
|
|||
numberOfBackupsToDelete++;
|
||||
|
||||
while (numberOfBackupsToDelete--) {
|
||||
this.entries.pop();
|
||||
this._entries.pop();
|
||||
if (!this._backupFiles) {
|
||||
yield this.getBackupFiles();
|
||||
}
|
||||
|
@ -341,25 +358,22 @@ this.PlacesBackups = {
|
|||
}
|
||||
|
||||
// Save bookmarks to a backup file.
|
||||
let backupFolderPath = yield this.getBackupFolder();
|
||||
let backupFolder = new FileUtils.File(backupFolderPath);
|
||||
let newBackupFile = backupFolder.clone();
|
||||
newBackupFile.append(newBackupFilename);
|
||||
|
||||
let backupFolder = yield this.getBackupFolder();
|
||||
let newBackupFile = OS.Path.join(backupFolder, newBackupFilename);
|
||||
let nodeCount = yield this.saveBookmarksToJSONFile(newBackupFile);
|
||||
// Rename the filename with metadata.
|
||||
let newFilenameWithMetaData = this._appendMetaDataToFilename(
|
||||
newBackupFilename,
|
||||
{ nodeCount: nodeCount });
|
||||
newBackupFile.moveTo(backupFolder, newFilenameWithMetaData);
|
||||
let newBackupFileWithMetadata = OS.Path.join(backupFolder, newFilenameWithMetaData);
|
||||
yield OS.File.move(newBackupFile, newBackupFileWithMetadata);
|
||||
|
||||
// Update internal cache.
|
||||
let newFileWithMetaData = backupFolder.clone();
|
||||
newFileWithMetaData.append(newFilenameWithMetaData);
|
||||
this.entries.pop();
|
||||
this.entries.push(newFileWithMetaData);
|
||||
let newFileWithMetaData = new localFileCtor(newBackupFileWithMetadata);
|
||||
this._entries.pop();
|
||||
this._entries.unshift(newFileWithMetaData);
|
||||
this._backupFiles.pop();
|
||||
this._backupFiles.push(newFileWithMetaData.path);
|
||||
this._backupFiles.unshift(newBackupFileWithMetadata);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
|
@ -400,22 +414,216 @@ this.PlacesBackups = {
|
|||
sourceMatches[4] == targetMatches[4]);
|
||||
},
|
||||
|
||||
_getBackupFileForSameDate:
|
||||
function PB__getBackupFileForSameDate(aFilename) {
|
||||
return Task.spawn(function() {
|
||||
let backupFolderPath = yield this.getBackupFolder();
|
||||
let iterator = new OS.File.DirectoryIterator(backupFolderPath);
|
||||
let backupFile;
|
||||
_getBackupFileForSameDate:
|
||||
function PB__getBackupFileForSameDate(aFilename) {
|
||||
return Task.spawn(function* () {
|
||||
let backupFolderPath = yield this.getBackupFolder();
|
||||
let iterator = new OS.File.DirectoryIterator(backupFolderPath);
|
||||
let backupFile;
|
||||
|
||||
yield iterator.forEach(function(aEntry) {
|
||||
if (this._isFilenameWithSameDate(aEntry.name, aFilename)) {
|
||||
backupFile = aEntry.path;
|
||||
return iterator.close();
|
||||
}
|
||||
}.bind(this));
|
||||
yield iterator.close();
|
||||
yield iterator.forEach(function(aEntry) {
|
||||
if (this._isFilenameWithSameDate(aEntry.name, aFilename)) {
|
||||
backupFile = aEntry.path;
|
||||
return iterator.close();
|
||||
}
|
||||
}.bind(this));
|
||||
yield iterator.close();
|
||||
|
||||
throw new Task.Result(backupFile);
|
||||
}.bind(this));
|
||||
}
|
||||
return backupFile;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a bookmarks tree representation usable to create backups in different
|
||||
* file formats. The root or the tree is PlacesUtils.placesRootId.
|
||||
* Items annotated with PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO and all of their
|
||||
* descendants are excluded.
|
||||
*
|
||||
* @return an object representing a tree with the places root as its root.
|
||||
* Each bookmark is represented by an object having these properties:
|
||||
* * id: the item id (make this not enumerable after bug 824502)
|
||||
* * title: the title
|
||||
* * guid: unique id
|
||||
* * parent: item id of the parent folder, not enumerable
|
||||
* * index: the position in the parent
|
||||
* * dateAdded: microseconds from the epoch
|
||||
* * lastModified: microseconds from the epoch
|
||||
* * type: type of the originating node as defined in PlacesUtils
|
||||
* The following properties exist only for a subset of bookmarks:
|
||||
* * annos: array of annotations
|
||||
* * uri: url
|
||||
* * keyword: associated keyword
|
||||
* * charset: last known charset
|
||||
* * tags: csv string of tags
|
||||
* * root: string describing whether this represents a root
|
||||
* * children: array of child items in a folder
|
||||
*/
|
||||
getBookmarksTree: function () {
|
||||
return Task.spawn(function* () {
|
||||
let dbFilePath = OS.Path.join(OS.Constants.Path.profileDir, "places.sqlite");
|
||||
let conn = yield Sqlite.openConnection({ path: dbFilePath,
|
||||
sharedMemoryCache: false });
|
||||
let rows = [];
|
||||
try {
|
||||
rows = yield conn.execute(
|
||||
"SELECT b.id, h.url, IFNULL(b.title, '') AS title, b.parent, " +
|
||||
"b.position AS [index], b.type, b.dateAdded, b.lastModified, b.guid, " +
|
||||
"( SELECT GROUP_CONCAT(t.title, ',') " +
|
||||
"FROM moz_bookmarks b2 " +
|
||||
"JOIN moz_bookmarks t ON t.id = +b2.parent AND t.parent = :tags_folder " +
|
||||
"WHERE b2.fk = h.id " +
|
||||
") AS tags, " +
|
||||
"EXISTS (SELECT 1 FROM moz_items_annos WHERE item_id = b.id LIMIT 1) AS has_annos, " +
|
||||
"( SELECT a.content FROM moz_annos a " +
|
||||
"JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id " +
|
||||
"WHERE place_id = h.id AND n.name = :charset_anno " +
|
||||
") AS charset " +
|
||||
"FROM moz_bookmarks b " +
|
||||
"LEFT JOIN moz_bookmarks p ON p.id = b.parent " +
|
||||
"LEFT JOIN moz_places h ON h.id = b.fk " +
|
||||
"WHERE b.id <> :tags_folder AND b.parent <> :tags_folder AND p.parent <> :tags_folder " +
|
||||
"ORDER BY b.parent, b.position",
|
||||
{ tags_folder: PlacesUtils.tagsFolderId,
|
||||
charset_anno: PlacesUtils.CHARSET_ANNO });
|
||||
} catch(e) {
|
||||
Cu.reportError("Unable to query the database " + e);
|
||||
} finally {
|
||||
yield conn.close();
|
||||
}
|
||||
|
||||
let startTime = Date.now();
|
||||
// Create a Map for lookup and recursive building of the tree.
|
||||
let itemsMap = new Map();
|
||||
for (let row of rows) {
|
||||
let id = row.getResultByName("id");
|
||||
try {
|
||||
let bookmark = sqliteRowToBookmarkObject(row);
|
||||
if (itemsMap.has(id)) {
|
||||
// Since children may be added before parents, we should merge with
|
||||
// the existing object.
|
||||
let original = itemsMap.get(id);
|
||||
for (prop in bookmark) {
|
||||
original[prop] = bookmark[prop];
|
||||
}
|
||||
bookmark = original;
|
||||
}
|
||||
else {
|
||||
itemsMap.set(id, bookmark);
|
||||
}
|
||||
|
||||
// Append bookmark to its parent.
|
||||
if (!itemsMap.has(bookmark.parent))
|
||||
itemsMap.set(bookmark.parent, {});
|
||||
let parent = itemsMap.get(bookmark.parent);
|
||||
if (!("children" in parent))
|
||||
parent.children = [];
|
||||
parent.children.push(bookmark);
|
||||
} catch (e) {
|
||||
Cu.reportError("Error while reading node " + id + " " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle excluded items, by removing entire subtrees pointed by them.
|
||||
function removeFromMap(id) {
|
||||
// Could have been removed by a previous call, since we can't
|
||||
// predict order of items in EXCLUDE_FROM_BACKUP_ANNO.
|
||||
if (itemsMap.has(id)) {
|
||||
let excludedItem = itemsMap.get(id);
|
||||
if (excludedItem.children) {
|
||||
for (let child of excludedItem.children) {
|
||||
removeFromMap(child.id);
|
||||
}
|
||||
}
|
||||
// Remove the excluded item from its parent's children...
|
||||
let parentItem = itemsMap.get(excludedItem.parent);
|
||||
parentItem.children = parentItem.children.filter(aChild => aChild.id != id);
|
||||
// ...then remove it from the map.
|
||||
itemsMap.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
for (let id of PlacesUtils.annotations.getItemsWithAnnotation(
|
||||
PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO)) {
|
||||
removeFromMap(id);
|
||||
}
|
||||
|
||||
// Report the time taken to build the tree. This doesn't take into
|
||||
// account the time spent in the query since that's off the main-thread.
|
||||
try {
|
||||
Services.telemetry
|
||||
.getHistogramById("PLACES_BACKUPS_BOOKMARKSTREE_MS")
|
||||
.add(Date.now() - startTime);
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to report telemetry.");
|
||||
}
|
||||
|
||||
return [itemsMap.get(PlacesUtils.placesRootId), itemsMap.size];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to convert a Sqlite.jsm row to a bookmark object
|
||||
* representation.
|
||||
*
|
||||
* @param aRow The Sqlite.jsm result row.
|
||||
*/
|
||||
function sqliteRowToBookmarkObject(aRow) {
|
||||
let bookmark = {};
|
||||
for (let p of [ "id" ,"guid", "title", "index", "dateAdded", "lastModified" ]) {
|
||||
bookmark[p] = aRow.getResultByName(p);
|
||||
}
|
||||
Object.defineProperty(bookmark, "parent",
|
||||
{ value: aRow.getResultByName("parent") });
|
||||
|
||||
let type = aRow.getResultByName("type");
|
||||
|
||||
// Add annotations.
|
||||
if (aRow.getResultByName("has_annos")) {
|
||||
try {
|
||||
bookmark.annos = PlacesUtils.getAnnotationsForItem(bookmark.id);
|
||||
} catch (e) {
|
||||
Cu.reportError("Unexpected error while reading annotations " + e);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case Ci.nsINavBookmarksService.TYPE_BOOKMARK:
|
||||
// TODO: What about shortcuts?
|
||||
bookmark.type = PlacesUtils.TYPE_X_MOZ_PLACE;
|
||||
// This will throw if we try to serialize an invalid url and the node will
|
||||
// just be skipped.
|
||||
bookmark.uri = NetUtil.newURI(aRow.getResultByName("url")).spec;
|
||||
// Keywords are cached, so this should be decently fast.
|
||||
let keyword = PlacesUtils.bookmarks.getKeywordForBookmark(bookmark.id);
|
||||
if (keyword)
|
||||
bookmark.keyword = keyword;
|
||||
let charset = aRow.getResultByName("charset");
|
||||
if (charset)
|
||||
bookmark.charset = charset;
|
||||
let tags = aRow.getResultByName("tags");
|
||||
if (tags)
|
||||
bookmark.tags = tags;
|
||||
break;
|
||||
case Ci.nsINavBookmarksService.TYPE_FOLDER:
|
||||
bookmark.type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER;
|
||||
|
||||
// Mark root folders.
|
||||
if (bookmark.id == PlacesUtils.placesRootId)
|
||||
bookmark.root = "placesRoot";
|
||||
else if (bookmark.id == PlacesUtils.bookmarksMenuFolderId)
|
||||
bookmark.root = "bookmarksMenuFolder";
|
||||
else if (bookmark.id == PlacesUtils.unfiledBookmarksFolderId)
|
||||
bookmark.root = "unfiledBookmarksFolder";
|
||||
else if (bookmark.id == PlacesUtils.toolbarFolderId)
|
||||
bookmark.root = "toolbarFolder";
|
||||
break;
|
||||
case Ci.nsINavBookmarksService.TYPE_SEPARATOR:
|
||||
bookmark.type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR;
|
||||
break;
|
||||
default:
|
||||
Cu.reportError("Unexpected bookmark type");
|
||||
break;
|
||||
}
|
||||
return bookmark;
|
||||
}
|
||||
|
|
|
@ -133,52 +133,6 @@
|
|||
this.mPageTextBox.max = print.printPreviewNumPages;
|
||||
|
||||
this.updateToolbar();
|
||||
|
||||
// Hide the ``Print...'' button when the underlying gfx code does not
|
||||
// support multiple devicecontext to be used concurrently
|
||||
// (e.g. printing and printpreview at the same time; required as
|
||||
// legacy support for unices.'s PostScript module
|
||||
// XXX the scaling widgets, and the orientation widgets on unices.
|
||||
var canPrint = true;
|
||||
try
|
||||
{
|
||||
var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
canPrint = prefs.getBoolPref("print.whileInPrintPreview");
|
||||
if (!canPrint)
|
||||
{
|
||||
// Ask the printerfeatures database if this printer device
|
||||
// supports multiple device instances which can be used
|
||||
// concurrently
|
||||
var smdci = prefs.getBoolPref("print.tmp.printerfeatures." +
|
||||
print.currentPrintSettings.printerName +
|
||||
".can_use_multiple_devicecontexts_concurrently");
|
||||
|
||||
// We can print from print preview when we can use multiple
|
||||
// devicecontext instances in parallel (regardless what
|
||||
// "print.whileInPrintPreview" may say here...)
|
||||
if (smdci)
|
||||
{
|
||||
canPrint = true;
|
||||
}
|
||||
}
|
||||
|
||||
} catch(e) {}
|
||||
|
||||
if (!canPrint)
|
||||
{
|
||||
// hide print button
|
||||
this.mPrintButton.setAttribute("hidden", "true");
|
||||
|
||||
// hide page setup button
|
||||
document.getAnonymousNodes(this)[1].setAttribute("hidden", "true");
|
||||
|
||||
// hide scale widgets (indices: 8, 9, 10, 11)
|
||||
// hide orient widgets (indices: 12, 13)
|
||||
for (var i = 8; i <= 13; ++i)
|
||||
{
|
||||
document.getAnonymousNodes(this)[i].setAttribute("hidden", "true");
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
|
|
|
@ -2844,6 +2844,30 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "PLACES: Number of keywords"
|
||||
},
|
||||
"PLACES_BACKUPS_DAYSFROMLAST": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
"n_values": 15,
|
||||
"description": "PLACES: Days from last backup"
|
||||
},
|
||||
"PLACES_BACKUPS_BOOKMARKSTREE_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"low": 50,
|
||||
"high": 2000,
|
||||
"n_buckets": 10,
|
||||
"extended_statistics_ok": true,
|
||||
"description": "PLACES: Time to build the bookmarks tree"
|
||||
},
|
||||
"PLACES_BACKUPS_TOJSON_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"low": 50,
|
||||
"high": 2000,
|
||||
"n_buckets": 10,
|
||||
"extended_statistics_ok": true,
|
||||
"description": "PLACES: Time to convert and write the backup"
|
||||
},
|
||||
"FENNEC_FAVICONS_COUNT": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<body onload="load();">
|
||||
<p id="display"></p>
|
||||
<iframe id="test"></iframe>
|
||||
<script type="text/javascript">
|
||||
|
@ -45,91 +45,99 @@ function make_test(param, expected) {
|
|||
});
|
||||
}
|
||||
|
||||
var iframe = document.getElementById("test");
|
||||
var gCallback = null;
|
||||
function run_test(test, cb) {
|
||||
iframe.src = "unsafeBidiFileName.sjs?name=" + encodeURIComponent(test.param);
|
||||
gCallback = cb;
|
||||
}
|
||||
|
||||
var gCounter = -1;
|
||||
function run_next_test() {
|
||||
if (++gCounter == gTests.length)
|
||||
finish_test();
|
||||
else
|
||||
run_test(gTests[gCounter], run_next_test);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
|
||||
const HELPERAPP_DIALOG_CID = SpecialPowers.wrap(SpecialPowers.Components).ID(SpecialPowers.Cc[HELPERAPP_DIALOG_CONTRACT].number);
|
||||
|
||||
const FAKE_CID = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(SpecialPowers.Ci.nsIUUIDGenerator).generateUUID();
|
||||
|
||||
function HelperAppLauncherDialog() {}
|
||||
HelperAppLauncherDialog.prototype = {
|
||||
REASON_CANTHANDLE: 0,
|
||||
REASON_SERVERREQUEST: 1,
|
||||
REASON_TYPESNIFFED: 2,
|
||||
show: function(aLauncher, aWindowContext, aReason) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var test = gTests[gCounter];
|
||||
is(aLauncher.suggestedFileName, test.expected,
|
||||
"The filename should be correctly sanitized");
|
||||
gCallback();
|
||||
},
|
||||
promptForSaveToFile: function(aLauncher, aWindowContext, aDefaultFileName, aSuggestedFileExtension, aForcePrompt) {
|
||||
return null;
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
if (aIID.equals(SpecialPowers.Ci.nsISupports) ||
|
||||
aIID.equals(SpecialPowers.Ci.nsIHelperAppLauncherDialog))
|
||||
return this;
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
|
||||
function load() {
|
||||
info("Started the load handler");
|
||||
var iframe = document.getElementById("test");
|
||||
var gCallback = null;
|
||||
function run_test(test, cb) {
|
||||
iframe.src = "unsafeBidiFileName.sjs?name=" + encodeURIComponent(test.param);
|
||||
gCallback = cb;
|
||||
}
|
||||
};
|
||||
|
||||
var factory = {
|
||||
createInstance: function(aOuter, aIID) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
if (aOuter != null)
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_AGGREGATION;
|
||||
return new HelperAppLauncherDialog().QueryInterface(aIID);
|
||||
var gCounter = -1;
|
||||
function run_next_test() {
|
||||
info("run_next_test called, gCounter = " + gCounter);
|
||||
if (++gCounter == gTests.length)
|
||||
finish_test();
|
||||
else
|
||||
run_test(gTests[gCounter], run_next_test);
|
||||
}
|
||||
};
|
||||
|
||||
dump("RegisterFactory...\n");
|
||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
||||
.registerFactory(FAKE_CID, "",
|
||||
HELPERAPP_DIALOG_CONTRACT,
|
||||
factory);
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
|
||||
function finish_test() {
|
||||
dump("UnregisterFactory...\n");
|
||||
const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
|
||||
const HELPERAPP_DIALOG_CID = SpecialPowers.wrap(SpecialPowers.Components).ID(SpecialPowers.Cc[HELPERAPP_DIALOG_CONTRACT].number);
|
||||
|
||||
const FAKE_CID = SpecialPowers.Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(SpecialPowers.Ci.nsIUUIDGenerator).generateUUID();
|
||||
|
||||
function HelperAppLauncherDialog() {}
|
||||
HelperAppLauncherDialog.prototype = {
|
||||
REASON_CANTHANDLE: 0,
|
||||
REASON_SERVERREQUEST: 1,
|
||||
REASON_TYPESNIFFED: 2,
|
||||
show: function(aLauncher, aWindowContext, aReason) {
|
||||
info("show() called");
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var test = gTests[gCounter];
|
||||
is(aLauncher.suggestedFileName, test.expected,
|
||||
"The filename should be correctly sanitized");
|
||||
gCallback();
|
||||
},
|
||||
promptForSaveToFile: function(aLauncher, aWindowContext, aDefaultFileName, aSuggestedFileExtension, aForcePrompt) {
|
||||
info("promptForSaveToFile called");
|
||||
return null;
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
info("QueryInterface called");
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
if (aIID.equals(SpecialPowers.Ci.nsISupports) ||
|
||||
aIID.equals(SpecialPowers.Ci.nsIHelperAppLauncherDialog))
|
||||
return this;
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
var factory = {
|
||||
createInstance: function(aOuter, aIID) {
|
||||
info("createInstance called");
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
if (aOuter != null)
|
||||
throw SpecialPowers.Cr.NS_ERROR_NO_AGGREGATION;
|
||||
return new HelperAppLauncherDialog().QueryInterface(aIID);
|
||||
}
|
||||
};
|
||||
|
||||
info("RegisterFactory...\n");
|
||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
||||
.registerFactory(HELPERAPP_DIALOG_CID, "",
|
||||
.registerFactory(FAKE_CID, "",
|
||||
HELPERAPP_DIALOG_CONTRACT,
|
||||
null);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
factory);
|
||||
|
||||
var i,j;
|
||||
|
||||
for (i = 0; i < tests.length; ++i) {
|
||||
for (j in unsafeBidiChars) {
|
||||
make_test(replace(tests[i], unsafeBidiChars[j]),
|
||||
sanitize(tests[i]));
|
||||
function finish_test() {
|
||||
info("UnregisterFactory...\n");
|
||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
||||
.registerFactory(HELPERAPP_DIALOG_CID, "",
|
||||
HELPERAPP_DIALOG_CONTRACT,
|
||||
null);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
var i,j;
|
||||
|
||||
for (i = 0; i < tests.length; ++i) {
|
||||
for (j in unsafeBidiChars) {
|
||||
make_test(replace(tests[i], unsafeBidiChars[j]),
|
||||
sanitize(tests[i]));
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
* 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/. */
|
||||
|
||||
/* Store per-printer features in temp. prefs vars that the
|
||||
* print dialog can pick them up... */
|
||||
#define SET_PRINTER_FEATURES_VIA_PREFS 1
|
||||
#define PRINTERFEATURES_PREF "print.tmp.printerfeatures"
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
#define FORCE_PR_LOG 1 /* Allow logging in the release build */
|
||||
#endif /* MOZ_LOGGING */
|
||||
|
@ -81,265 +76,6 @@ protected:
|
|||
static nsTArray<nsString>* mGlobalPrinterList;
|
||||
};
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
/* "Prototype" for the new nsPrinterFeatures service */
|
||||
class nsPrinterFeatures {
|
||||
public:
|
||||
nsPrinterFeatures( const char *printername );
|
||||
~nsPrinterFeatures() {}
|
||||
|
||||
/* Does this printer allow to set/change the paper size ? */
|
||||
void SetCanChangePaperSize( bool aCanSetPaperSize );
|
||||
/* Does this Mozilla print module allow set/change the paper size ? */
|
||||
void SetSupportsPaperSizeChange( bool aSupportsPaperSizeChange );
|
||||
/* Set number of paper size records and the records itself */
|
||||
void SetNumPaperSizeRecords( int32_t aCount );
|
||||
void SetPaperRecord( int32_t aIndex, const char *aName, int32_t aWidthMM, int32_t aHeightMM, bool aIsInch );
|
||||
|
||||
/* Does this printer allow to set/change the content orientation ? */
|
||||
void SetCanChangeOrientation( bool aCanSetOrientation );
|
||||
/* Does this Mozilla print module allow set/change the content orientation ? */
|
||||
void SetSupportsOrientationChange( bool aSupportsOrientationChange );
|
||||
/* Set number of orientation records and the records itself */
|
||||
void SetNumOrientationRecords( int32_t aCount );
|
||||
void SetOrientationRecord( int32_t aIndex, const char *aName );
|
||||
|
||||
/* Does this printer allow to set/change the plex mode ? */
|
||||
void SetCanChangePlex( bool aCanSetPlex );
|
||||
/* Does this Mozilla print module allow set/change the plex mode ? */
|
||||
void SetSupportsPlexChange( bool aSupportsPlexChange );
|
||||
/* Set number of plex records and the records itself */
|
||||
void SetNumPlexRecords( int32_t aCount );
|
||||
void SetPlexRecord( int32_t aIndex, const char *aName );
|
||||
|
||||
/* Does this printer allow to set/change the resolution name ? */
|
||||
void SetCanChangeResolutionName( bool aCanSetResolutionName );
|
||||
/* Does this Mozilla print module allow set/change the resolution name ? */
|
||||
void SetSupportsResolutionNameChange( bool aSupportsResolutionChange );
|
||||
/* Set number of resolution records and the records itself */
|
||||
void SetNumResolutionNameRecords( int32_t aCount );
|
||||
void SetResolutionNameRecord( int32_t aIndex, const char *aName );
|
||||
|
||||
/* Does this printer allow to set/change the colorspace ? */
|
||||
void SetCanChangeColorspace( bool aCanSetColorspace );
|
||||
/* Does this Mozilla print module allow set/change the colorspace ? */
|
||||
void SetSupportsColorspaceChange( bool aSupportsColorspace );
|
||||
/* Set number of colorspace records and the records itself */
|
||||
void SetNumColorspaceRecords( int32_t aCount );
|
||||
void SetColorspaceRecord( int32_t aIndex, const char *aName );
|
||||
|
||||
/* Does this device allow to set/change the usage of the internal grayscale mode ? */
|
||||
void SetCanChangePrintInColor( bool aCanSetPrintInColor );
|
||||
/* Does this printer allow to set/change the usage of the internal grayscale mode ? */
|
||||
void SetSupportsPrintInColorChange( bool aSupportPrintInColorChange );
|
||||
|
||||
/* Does this device allow to set/change the usage of font download to the printer? */
|
||||
void SetCanChangeDownloadFonts( bool aCanSetDownloadFonts );
|
||||
/* Does this printer allow to set/change the usage of font download to the printer? */
|
||||
void SetSupportsDownloadFontsChange( bool aSupportDownloadFontsChange );
|
||||
|
||||
/* Does this device allow to set/change the job title ? */
|
||||
void SetCanChangeJobTitle( bool aCanSetJobTitle );
|
||||
/* Does this printer allow to set/change the job title ? */
|
||||
void SetSupportsJobTitleChange( bool aSupportJobTitleChange );
|
||||
|
||||
/* Does this device allow to set/change the spooler command ? */
|
||||
void SetCanChangeSpoolerCommand( bool aCanSetSpoolerCommand );
|
||||
/* Does this printer allow to set/change the spooler command ? */
|
||||
void SetSupportsSpoolerCommandChange( bool aSupportSpoolerCommandChange );
|
||||
|
||||
/* Does this device allow to set/change number of copies for an document ? */
|
||||
void SetCanChangeNumCopies( bool aCanSetNumCopies );
|
||||
|
||||
private:
|
||||
/* private helper methods */
|
||||
void SetBoolValue( const char *tagname, bool value );
|
||||
void SetIntValue( const char *tagname, int32_t value );
|
||||
void SetCharValue( const char *tagname, const char *value );
|
||||
|
||||
nsXPIDLCString mPrinterName;
|
||||
};
|
||||
|
||||
void nsPrinterFeatures::SetBoolValue( const char *tagname, bool value )
|
||||
{
|
||||
nsPrintfCString prefName(PRINTERFEATURES_PREF ".%s.%s",
|
||||
mPrinterName.get(), tagname);
|
||||
Preferences::SetBool(prefName.get(), value);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetIntValue( const char *tagname, int32_t value )
|
||||
{
|
||||
nsPrintfCString prefName(PRINTERFEATURES_PREF ".%s.%s",
|
||||
mPrinterName.get(), tagname);
|
||||
Preferences::SetInt(prefName.get(), value);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCharValue( const char *tagname, const char *value )
|
||||
{
|
||||
nsPrintfCString prefName(PRINTERFEATURES_PREF ".%s.%s",
|
||||
mPrinterName.get(), tagname);
|
||||
Preferences::SetCString(prefName.get(), value);
|
||||
}
|
||||
|
||||
nsPrinterFeatures::nsPrinterFeatures( const char *printername )
|
||||
{
|
||||
DO_PR_DEBUG_LOG(("nsPrinterFeatures::nsPrinterFeatures('%s')\n", printername));
|
||||
mPrinterName.Assign(printername);
|
||||
|
||||
SetBoolValue("has_special_printerfeatures", true);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangePaperSize( bool aCanSetPaperSize )
|
||||
{
|
||||
SetBoolValue("can_change_paper_size", aCanSetPaperSize);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsPaperSizeChange( bool aSupportsPaperSizeChange )
|
||||
{
|
||||
SetBoolValue("supports_paper_size_change", aSupportsPaperSizeChange);
|
||||
}
|
||||
|
||||
/* Set number of paper size records and the records itself */
|
||||
void nsPrinterFeatures::SetNumPaperSizeRecords( int32_t aCount )
|
||||
{
|
||||
SetIntValue("paper.count", aCount);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetPaperRecord(int32_t aIndex, const char *aPaperName, int32_t aWidthMM, int32_t aHeightMM, bool aIsInch)
|
||||
{
|
||||
SetCharValue(nsPrintfCString("paper.%d.name", aIndex).get(), aPaperName);
|
||||
SetIntValue( nsPrintfCString("paper.%d.width_mm", aIndex).get(), aWidthMM);
|
||||
SetIntValue( nsPrintfCString("paper.%d.height_mm", aIndex).get(), aHeightMM);
|
||||
SetBoolValue(nsPrintfCString("paper.%d.is_inch", aIndex).get(), aIsInch);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeOrientation( bool aCanSetOrientation )
|
||||
{
|
||||
SetBoolValue("can_change_orientation", aCanSetOrientation);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsOrientationChange( bool aSupportsOrientationChange )
|
||||
{
|
||||
SetBoolValue("supports_orientation_change", aSupportsOrientationChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetNumOrientationRecords( int32_t aCount )
|
||||
{
|
||||
SetIntValue("orientation.count", aCount);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetOrientationRecord( int32_t aIndex, const char *aOrientationName )
|
||||
{
|
||||
SetCharValue(nsPrintfCString("orientation.%d.name", aIndex).get(), aOrientationName);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangePlex( bool aCanSetPlex )
|
||||
{
|
||||
SetBoolValue("can_change_plex", aCanSetPlex);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsPlexChange( bool aSupportsPlexChange )
|
||||
{
|
||||
SetBoolValue("supports_plex_change", aSupportsPlexChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetNumPlexRecords( int32_t aCount )
|
||||
{
|
||||
SetIntValue("plex.count", aCount);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetPlexRecord( int32_t aIndex, const char *aPlexName )
|
||||
{
|
||||
SetCharValue(nsPrintfCString("plex.%d.name", aIndex).get(), aPlexName);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeResolutionName( bool aCanSetResolutionName )
|
||||
{
|
||||
SetBoolValue("can_change_resolution", aCanSetResolutionName);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsResolutionNameChange( bool aSupportsResolutionNameChange )
|
||||
{
|
||||
SetBoolValue("supports_resolution_change", aSupportsResolutionNameChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetNumResolutionNameRecords( int32_t aCount )
|
||||
{
|
||||
SetIntValue("resolution.count", aCount);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetResolutionNameRecord( int32_t aIndex, const char *aResolutionName )
|
||||
{
|
||||
SetCharValue(nsPrintfCString("resolution.%d.name", aIndex).get(), aResolutionName);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeColorspace( bool aCanSetColorspace )
|
||||
{
|
||||
SetBoolValue("can_change_colorspace", aCanSetColorspace);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsColorspaceChange( bool aSupportsColorspaceChange )
|
||||
{
|
||||
SetBoolValue("supports_colorspace_change", aSupportsColorspaceChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetNumColorspaceRecords( int32_t aCount )
|
||||
{
|
||||
SetIntValue("colorspace.count", aCount);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetColorspaceRecord( int32_t aIndex, const char *aColorspace )
|
||||
{
|
||||
SetCharValue(nsPrintfCString("colorspace.%d.name", aIndex).get(), aColorspace);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeDownloadFonts( bool aCanSetDownloadFonts )
|
||||
{
|
||||
SetBoolValue("can_change_downloadfonts", aCanSetDownloadFonts);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsDownloadFontsChange( bool aSupportDownloadFontsChange )
|
||||
{
|
||||
SetBoolValue("supports_downloadfonts_change", aSupportDownloadFontsChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangePrintInColor( bool aCanSetPrintInColor )
|
||||
{
|
||||
SetBoolValue("can_change_printincolor", aCanSetPrintInColor);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsPrintInColorChange( bool aSupportPrintInColorChange )
|
||||
{
|
||||
SetBoolValue("supports_printincolor_change", aSupportPrintInColorChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeSpoolerCommand( bool aCanSetSpoolerCommand )
|
||||
{
|
||||
SetBoolValue("can_change_spoolercommand", aCanSetSpoolerCommand);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsSpoolerCommandChange( bool aSupportSpoolerCommandChange )
|
||||
{
|
||||
SetBoolValue("supports_spoolercommand_change", aSupportSpoolerCommandChange);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeJobTitle( bool aCanSetJobTitle )
|
||||
{
|
||||
SetBoolValue("can_change_jobtitle", aCanSetJobTitle);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetSupportsJobTitleChange( bool aSupportsJobTitle )
|
||||
{
|
||||
SetBoolValue("supports_jobtitle_change", aSupportsJobTitle);
|
||||
}
|
||||
|
||||
void nsPrinterFeatures::SetCanChangeNumCopies( bool aCanSetNumCopies )
|
||||
{
|
||||
SetBoolValue("can_change_num_copies", aCanSetNumCopies);
|
||||
}
|
||||
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
//---------------
|
||||
// static members
|
||||
GlobalPrinters GlobalPrinters::mGlobalPrinters;
|
||||
|
@ -749,15 +485,6 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_
|
|||
printerName.Cut(0, slash + 1);
|
||||
}
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
/* Defaults to FALSE */
|
||||
nsPrintfCString prefName(
|
||||
PRINTERFEATURES_PREF ".%s.has_special_printerfeatures",
|
||||
fullPrinterName.get());
|
||||
Preferences::SetBool(prefName.get(), false);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
|
||||
/* Set filename */
|
||||
nsAutoCString filename;
|
||||
if (NS_FAILED(CopyPrinterCharPref(nullptr, printerName, "filename", filename))) {
|
||||
|
@ -779,20 +506,6 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_
|
|||
if (type == pmPostScript) {
|
||||
DO_PR_DEBUG_LOG(("InitPrintSettingsFromPrinter() for PostScript printer\n"));
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
nsPrinterFeatures printerFeatures(fullPrinterName);
|
||||
|
||||
printerFeatures.SetSupportsPaperSizeChange(true);
|
||||
printerFeatures.SetSupportsOrientationChange(true);
|
||||
printerFeatures.SetSupportsPlexChange(false);
|
||||
printerFeatures.SetSupportsResolutionNameChange(false);
|
||||
printerFeatures.SetSupportsColorspaceChange(false);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangeOrientation(true);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
nsAutoCString orientation;
|
||||
if (NS_SUCCEEDED(CopyPrinterCharPref("postscript", printerName,
|
||||
"orientation", orientation))) {
|
||||
|
@ -809,48 +522,18 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetOrientationRecord(0, "portrait");
|
||||
printerFeatures.SetOrientationRecord(1, "landscape");
|
||||
printerFeatures.SetNumOrientationRecords(2);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
/* PostScript module does not support changing the plex mode... */
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangePlex(false);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
DO_PR_DEBUG_LOG(("setting default plex to '%s'\n", "default"));
|
||||
aPrintSettings->SetPlexName(MOZ_UTF16("default"));
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetPlexRecord(0, "default");
|
||||
printerFeatures.SetNumPlexRecords(1);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
/* PostScript module does not support changing the resolution mode... */
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangeResolutionName(false);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
DO_PR_DEBUG_LOG(("setting default resolution to '%s'\n", "default"));
|
||||
aPrintSettings->SetResolutionName(MOZ_UTF16("default"));
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetResolutionNameRecord(0, "default");
|
||||
printerFeatures.SetNumResolutionNameRecords(1);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
/* PostScript module does not support changing the colorspace... */
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangeColorspace(false);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
DO_PR_DEBUG_LOG(("setting default colorspace to '%s'\n", "default"));
|
||||
aPrintSettings->SetColorspace(MOZ_UTF16("default"));
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetColorspaceRecord(0, "default");
|
||||
printerFeatures.SetNumColorspaceRecords(1);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangePaperSize(true);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
nsAutoCString papername;
|
||||
if (NS_SUCCEEDED(CopyPrinterCharPref("postscript", printerName,
|
||||
"paper_size", papername))) {
|
||||
|
@ -867,36 +550,10 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_
|
|||
else {
|
||||
DO_PR_DEBUG_LOG(("Unknown paper size '%s' given.\n", papername.get()));
|
||||
}
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
paper.First();
|
||||
int count = 0;
|
||||
while (!paper.AtEnd())
|
||||
{
|
||||
printerFeatures.SetPaperRecord(count++, paper.Name(),
|
||||
(int)paper.Width_mm(), (int)paper.Height_mm(), !paper.IsMetric());
|
||||
paper.Next();
|
||||
}
|
||||
printerFeatures.SetNumPaperSizeRecords(count);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
}
|
||||
|
||||
bool hasSpoolerCmd = (nsPSPrinterList::kTypePS ==
|
||||
nsPSPrinterList::GetPrinterType(fullPrinterName));
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetSupportsSpoolerCommandChange(hasSpoolerCmd);
|
||||
printerFeatures.SetCanChangeSpoolerCommand(hasSpoolerCmd);
|
||||
|
||||
/* Postscript module does not pass the job title to lpr */
|
||||
printerFeatures.SetSupportsJobTitleChange(false);
|
||||
printerFeatures.SetCanChangeJobTitle(false);
|
||||
/* Postscript module has no control over builtin fonts yet */
|
||||
printerFeatures.SetSupportsDownloadFontsChange(false);
|
||||
printerFeatures.SetCanChangeDownloadFonts(false);
|
||||
/* Postscript module does not support multiple colorspaces
|
||||
* so it has to use the old way */
|
||||
printerFeatures.SetSupportsPrintInColorChange(true);
|
||||
printerFeatures.SetCanChangePrintInColor(true);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
if (hasSpoolerCmd) {
|
||||
nsAutoCString command;
|
||||
|
@ -908,10 +565,6 @@ NS_IMETHODIMP nsPrinterEnumeratorGTK::InitPrintSettingsFromPrinter(const char16_
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef SET_PRINTER_FEATURES_VIA_PREFS
|
||||
printerFeatures.SetCanChangeNumCopies(true);
|
||||
#endif /* SET_PRINTER_FEATURES_VIA_PREFS */
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче