mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
Merge m-c to b2g-inbound
This commit is contained in:
commit
3887604616
@ -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);
|
||||
|
@ -249,6 +249,11 @@ toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe {
|
||||
display: none;
|
||||
}
|
||||
|
||||
toolbarpaletteitem[removable="false"] {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#bookmarks-toolbar-placeholder,
|
||||
toolbarpaletteitem > #personal-bookmarks > #PlacesToolbar,
|
||||
#personal-bookmarks[cui-areatype="menu-panel"] > #PlacesToolbar,
|
||||
|
@ -660,6 +660,9 @@ CustomizeMode.prototype = {
|
||||
wrapper.setAttribute("flex", aNode.getAttribute("flex"));
|
||||
}
|
||||
|
||||
let removable = aPlace == "palette" || CustomizableUI.isWidgetRemovable(aNode);
|
||||
wrapper.setAttribute("removable", removable);
|
||||
|
||||
let contextMenuAttrName = aNode.getAttribute("context") ? "context" :
|
||||
aNode.getAttribute("contextmenu") ? "contextmenu" : "";
|
||||
let currentContextMenu = aNode.getAttribute(contextMenuAttrName);
|
||||
@ -1036,14 +1039,17 @@ CustomizeMode.prototype = {
|
||||
item = item.parentNode;
|
||||
}
|
||||
|
||||
if (item.classList.contains(kPlaceholderClass)) {
|
||||
let draggedItem = item.firstChild;
|
||||
let placeForItem = CustomizableUI.getPlaceForItem(item);
|
||||
let isRemovable = placeForItem == "palette" ||
|
||||
CustomizableUI.isWidgetRemovable(draggedItem);
|
||||
if (item.classList.contains(kPlaceholderClass) || !isRemovable) {
|
||||
return;
|
||||
}
|
||||
|
||||
let dt = aEvent.dataTransfer;
|
||||
let documentId = aEvent.target.ownerDocument.documentElement.id;
|
||||
let draggedItem = item.firstChild;
|
||||
let isInToolbar = CustomizableUI.getPlaceForItem(item) == "toolbar";
|
||||
let isInToolbar = placeForItem == "toolbar";
|
||||
|
||||
dt.mozSetDataAt(kDragDataTypePrefix + documentId, draggedItem.id, 0);
|
||||
dt.effectAllowed = "move";
|
||||
@ -1618,7 +1624,8 @@ CustomizeMode.prototype = {
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
doc.documentElement.setAttribute("customizing-movingItem", true);
|
||||
let item = this._getWrapper(aEvent.target);
|
||||
if (item && !item.classList.contains(kPlaceholderClass)) {
|
||||
if (item && !item.classList.contains(kPlaceholderClass) &&
|
||||
item.getAttribute("removable") == "true") {
|
||||
item.setAttribute("mousedown", "true");
|
||||
}
|
||||
},
|
||||
|
@ -14,6 +14,7 @@ add_task(function() {
|
||||
skippedItem.id = "test-skipintoolbarset-item";
|
||||
skippedItem.setAttribute("label", "Test");
|
||||
skippedItem.setAttribute("skipintoolbarset", "true");
|
||||
skippedItem.setAttribute("removable", "true");
|
||||
navbar.customizationTarget.appendChild(skippedItem);
|
||||
let downloadsButton = document.getElementById("downloads-button");
|
||||
yield startCustomizing();
|
||||
|
@ -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,7 +256,6 @@ BrowserGlue.prototype = {
|
||||
this._onPlacesShutdown();
|
||||
break;
|
||||
case "idle":
|
||||
if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
|
||||
this._backupBookmarks();
|
||||
break;
|
||||
case "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;
|
||||
}
|
||||
);
|
||||
|
||||
// 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.
|
||||
// Support legacy bookmarks.html format for apps that depend on that format.
|
||||
try {
|
||||
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;
|
||||
}
|
||||
// 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)
|
||||
);
|
||||
}
|
||||
|
||||
// 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>
|
||||
|
@ -48,6 +48,7 @@ let Elements = {};
|
||||
["contentViewport", "content-viewport"],
|
||||
["progress", "progress-control"],
|
||||
["progressContainer", "progress-container"],
|
||||
["feedbackLabel", "feedback-label"],
|
||||
].forEach(function (aElementGlobal) {
|
||||
let [name, id] = aElementGlobal;
|
||||
XPCOMUtils.defineLazyGetter(Elements, name, function() {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -52,6 +52,17 @@ var SettingsCharm = {
|
||||
onselected: function() FlyoutPanelsUI.show('AboutFlyoutPanel')
|
||||
});
|
||||
|
||||
// Feedback
|
||||
this.addEntry({
|
||||
// feedbackLabel is a temporary measure to expose this string
|
||||
// from the baseMenuOverlay.dtd
|
||||
label: Elements.feedbackLabel.value,
|
||||
onselected: function() {
|
||||
let url = Elements.feedbackLabel.getAttribute("href");
|
||||
BrowserUI.addAndShowTab(url, Browser.selectedTab);
|
||||
}
|
||||
});
|
||||
|
||||
// Help
|
||||
this.addEntry({
|
||||
label: Strings.browser.GetStringFromName("helpOnlineCharm"),
|
||||
|
@ -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>
|
||||
|
@ -109,7 +109,7 @@ HelperAppLauncherDialog.prototype = {
|
||||
let chromeWin = this._getChromeWindow(window).wrappedJSObject;
|
||||
let notificationBox = chromeWin.Browser.getNotificationBox();
|
||||
let document = notificationBox.ownerDocument;
|
||||
downloadSize = this._getDownloadSize(aLauncher.contentLength);
|
||||
let downloadSize = this._getDownloadSize(aLauncher.contentLength);
|
||||
|
||||
let msg = browserBundle.GetStringFromName("alertDownloadSave2");
|
||||
|
||||
|
@ -39,6 +39,8 @@
|
||||
@AB_CD@.jar:
|
||||
relativesrcdir browser/locales:
|
||||
locale/browser/syncBrand.dtd (%chrome/browser/syncBrand.dtd)
|
||||
# Temporary hack to provide a 'feedback' string
|
||||
locale/browser/baseMenuOverlay.dtd (%chrome/browser/baseMenuOverlay.dtd)
|
||||
locale/browser/netError.dtd (%chrome/overrides/netError.dtd)
|
||||
% override chrome://global/locale/netError.dtd chrome://browser/locale/netError.dtd
|
||||
locale/browser/appstrings.properties (%chrome/overrides/appstrings.properties)
|
||||
|
@ -298,6 +298,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
||||
|
||||
#PanelUI-footer {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
flex-direction: column;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 -1px 0 rgba(0,0,0,.15);
|
||||
|
@ -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>
|
180
docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
Normal file
180
docshell/test/chrome/test_viewsource_forbidden_in_iframe.xul
Normal file
@ -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);
|
||||
|
38
js/src/jit-test/tests/debug/Source-introductionType.js
Normal file
38
js/src/jit-test/tests/debug/Source-introductionType.js
Normal file
@ -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');
|
||||
|
17
js/src/jit-test/tests/parallel/bug944975.js
Normal file
17
js/src/jit-test/tests/parallel/bug944975.js
Normal file
@ -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",
|
||||
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");
|
||||
|
@ -52,6 +52,10 @@ public class AboutPages {
|
||||
return url.startsWith(READER);
|
||||
}
|
||||
|
||||
public static final boolean isAboutPrivateBrowsing(final String url) {
|
||||
return PRIVATEBROWSING.equals(url);
|
||||
}
|
||||
|
||||
private static final String[] DEFAULT_ICON_PAGES = new String[] {
|
||||
HOME,
|
||||
|
||||
|
@ -34,6 +34,7 @@ import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GamepadUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.MenuUtils;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
@ -2132,6 +2133,15 @@ abstract public class BrowserApp extends GeckoApp
|
||||
share.setEnabled(false);
|
||||
saveAsPDF.setEnabled(false);
|
||||
findInPage.setEnabled(false);
|
||||
|
||||
// NOTE: Use MenuUtils.safeSetEnabled because some actions might
|
||||
// be on the BrowserToolbar context menu
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.page, false);
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, false);
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, false);
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.site_settings, false);
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2159,6 +2169,14 @@ abstract public class BrowserApp extends GeckoApp
|
||||
share.setEnabled(!(scheme.equals("about") || scheme.equals("chrome") ||
|
||||
scheme.equals("file") || scheme.equals("resource")));
|
||||
|
||||
// NOTE: Use MenuUtils.safeSetEnabled because some actions might
|
||||
// be on the BrowserToolbar context menu
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.page, !isAboutHome(tab));
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, tab.hasFeeds());
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, tab.hasOpenSearch());
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.site_settings, !isAboutHome(tab));
|
||||
MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, !isAboutHome(tab));
|
||||
|
||||
// Action providers are available only ICS+.
|
||||
if (Build.VERSION.SDK_INT >= 14) {
|
||||
GeckoActionProvider provider = (GeckoActionProvider) share.getActionProvider();
|
||||
@ -2355,6 +2373,13 @@ abstract public class BrowserApp extends GeckoApp
|
||||
return true;
|
||||
}
|
||||
|
||||
// We have a few menu items that can also be in the context menu. If
|
||||
// we have not already handled the item, give the context menu handler
|
||||
// a chance.
|
||||
if (onContextItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
@ -648,7 +648,8 @@ public class Tab {
|
||||
|
||||
private static boolean shouldShowProgress(final String url) {
|
||||
return AboutPages.isAboutHome(url) ||
|
||||
AboutPages.isAboutReader(url);
|
||||
AboutPages.isAboutReader(url) ||
|
||||
AboutPages.isAboutPrivateBrowsing(url);
|
||||
}
|
||||
|
||||
void handleDocumentStart(boolean showProgress, String url) {
|
||||
|
@ -43,9 +43,9 @@ public class PanelListRow extends TwoLineRow {
|
||||
final String title = cursor.getString(titleIndex);
|
||||
setTitle(title);
|
||||
|
||||
int urlIndex = cursor.getColumnIndexOrThrow(HomeItems.URL);
|
||||
final String url = cursor.getString(urlIndex);
|
||||
setDescription(url);
|
||||
int descriptionIndex = cursor.getColumnIndexOrThrow(HomeItems.DESCRIPTION);
|
||||
final String description = cursor.getString(descriptionIndex);
|
||||
setDescription(description);
|
||||
|
||||
int imageIndex = cursor.getColumnIndexOrThrow(HomeItems.IMAGE_URL);
|
||||
final String imageUrl = cursor.getString(imageIndex);
|
||||
|
@ -210,6 +210,7 @@ size. -->
|
||||
<!ENTITY save_as_pdf "Save as PDF">
|
||||
<!ENTITY find_in_page "Find in Page">
|
||||
<!ENTITY desktop_mode "Request Desktop Site">
|
||||
<!ENTITY page "Page">
|
||||
<!ENTITY tools "Tools">
|
||||
<!ENTITY new_tab "New Tab">
|
||||
<!ENTITY new_private_tab "New Private Tab">
|
||||
|
@ -52,6 +52,7 @@ gujar.sources += [
|
||||
'util/INIParser.java',
|
||||
'util/INISection.java',
|
||||
'util/JSONUtils.java',
|
||||
'util/MenuUtils.java',
|
||||
'util/NonEvictingLruCache.java',
|
||||
'util/ProxySelector.java',
|
||||
'util/StringUtils.java',
|
||||
|
@ -47,6 +47,28 @@
|
||||
android:title="@string/desktop_mode"
|
||||
android:checkable="true" />
|
||||
|
||||
<item android:id="@+id/page"
|
||||
android:title="@string/page"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
||||
<menu>
|
||||
|
||||
<item android:id="@+id/subscribe"
|
||||
android:title="@string/contextmenu_subscribe"/>
|
||||
|
||||
<item android:id="@+id/add_search_engine"
|
||||
android:title="@string/contextmenu_add_search_engine"/>
|
||||
|
||||
<item android:id="@+id/site_settings"
|
||||
android:title="@string/contextmenu_site_settings" />
|
||||
|
||||
<item android:id="@+id/add_to_launcher"
|
||||
android:title="@string/contextmenu_add_to_launcher"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/tools"
|
||||
android:title="@string/tools"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
@ -47,6 +47,28 @@
|
||||
android:title="@string/desktop_mode"
|
||||
android:checkable="true" />
|
||||
|
||||
<item android:id="@+id/page"
|
||||
android:title="@string/page"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
||||
<menu>
|
||||
|
||||
<item android:id="@+id/subscribe"
|
||||
android:title="@string/contextmenu_subscribe"/>
|
||||
|
||||
<item android:id="@+id/add_search_engine"
|
||||
android:title="@string/contextmenu_add_search_engine"/>
|
||||
|
||||
<item android:id="@+id/site_settings"
|
||||
android:title="@string/contextmenu_site_settings" />
|
||||
|
||||
<item android:id="@+id/add_to_launcher"
|
||||
android:title="@string/contextmenu_add_to_launcher"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/tools"
|
||||
android:title="@string/tools"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/pasteandgo"
|
||||
android:title="@string/contextmenu_pasteandgo"/>
|
||||
|
||||
<item android:id="@+id/paste"
|
||||
android:title="@string/contextmenu_paste"/>
|
||||
|
||||
<item android:id="@+id/copyurl"
|
||||
android:title="@string/contextmenu_copyurl"/>
|
||||
|
||||
<item android:id="@+id/add_to_launcher"
|
||||
android:title="@string/contextmenu_add_to_launcher"/>
|
||||
|
||||
</menu>
|
@ -47,6 +47,29 @@
|
||||
android:title="@string/desktop_mode"
|
||||
android:checkable="true" />
|
||||
|
||||
|
||||
<item android:id="@+id/page"
|
||||
android:title="@string/page"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
||||
<menu>
|
||||
|
||||
<item android:id="@+id/subscribe"
|
||||
android:title="@string/contextmenu_subscribe"/>
|
||||
|
||||
<item android:id="@+id/add_search_engine"
|
||||
android:title="@string/contextmenu_add_search_engine"/>
|
||||
|
||||
<item android:id="@+id/site_settings"
|
||||
android:title="@string/contextmenu_site_settings" />
|
||||
|
||||
<item android:id="@+id/add_to_launcher"
|
||||
android:title="@string/contextmenu_add_to_launcher"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
<item android:id="@+id/tools"
|
||||
android:title="@string/tools"
|
||||
android:icon="@drawable/ic_menu_tools">
|
||||
|
@ -77,6 +77,7 @@
|
||||
<string name="save_as_pdf">&save_as_pdf;</string>
|
||||
<string name="find_in_page">&find_in_page;</string>
|
||||
<string name="desktop_mode">&desktop_mode;</string>
|
||||
<string name="page">&page;</string>
|
||||
<string name="tools">&tools;</string>
|
||||
|
||||
<string name="find_text">&find_text;</string>
|
||||
|
@ -166,6 +166,7 @@ public class StringHelper {
|
||||
|
||||
// Android 3.0+
|
||||
public static final String TOOLS_LABEL = "Tools";
|
||||
public static final String PAGE_LABEL = "Page";
|
||||
|
||||
// Android 2.3 and lower only
|
||||
public static final String MORE_LABEL = "More";
|
||||
|
@ -107,9 +107,16 @@ public class testClearPrivateData extends PixelTest {
|
||||
|
||||
//Verify if there are settings to be clear if so clear them from the URL bar context menu
|
||||
public void checkOption(String option, String button) {
|
||||
if (mDevice.version.equals("2.x")) {
|
||||
// Use the context menu in pre-11
|
||||
final View toolbarView = mSolo.getView("browser_toolbar");
|
||||
mSolo.clickLongOnView(toolbarView);
|
||||
mAsserter.ok(waitForText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]), "Waiting for the pop-up to open", "Pop up was openend");
|
||||
mAsserter.ok(waitForText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]), "Waiting for the pop-up to open", "Pop up was opened");
|
||||
} else {
|
||||
// Use the Page menu in 11+
|
||||
selectMenuItem(StringHelper.PAGE_LABEL);
|
||||
mAsserter.ok(waitForText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]), "Waiting for the submenu to open", "Submenu was opened");
|
||||
}
|
||||
mSolo.clickOnText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]);
|
||||
mAsserter.ok(waitForText(option), "Verify that the option: " + option + " is in the list", "The option is in the list. There are settings to clear");
|
||||
mSolo.clickOnButton(button);
|
||||
|
@ -24,6 +24,7 @@ import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.OnTitleChangeListener;
|
||||
import org.mozilla.gecko.toolbar.ToolbarDisplayLayout.UpdateFlags;
|
||||
import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.MenuUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.widget.GeckoImageButton;
|
||||
@ -249,6 +250,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Use MenuUtils.safeSetVisible because some actions might
|
||||
// be on the Page menu
|
||||
|
||||
MenuInflater inflater = mActivity.getMenuInflater();
|
||||
inflater.inflate(R.menu.titlebar_contextmenu, menu);
|
||||
|
||||
@ -263,22 +267,22 @@ public class BrowserToolbar extends GeckoRelativeLayout
|
||||
String url = tab.getURL();
|
||||
if (url == null) {
|
||||
menu.findItem(R.id.copyurl).setVisible(false);
|
||||
menu.findItem(R.id.share).setVisible(false);
|
||||
menu.findItem(R.id.add_to_launcher).setVisible(false);
|
||||
MenuUtils.safeSetVisible(menu, R.id.share, false);
|
||||
}
|
||||
|
||||
menu.findItem(R.id.subscribe).setVisible(tab.hasFeeds());
|
||||
menu.findItem(R.id.add_search_engine).setVisible(tab.hasOpenSearch());
|
||||
MenuUtils.safeSetVisible(menu, R.id.subscribe, tab.hasFeeds());
|
||||
MenuUtils.safeSetVisible(menu, R.id.add_search_engine, tab.hasOpenSearch());
|
||||
} else {
|
||||
// if there is no tab, remove anything tab dependent
|
||||
menu.findItem(R.id.copyurl).setVisible(false);
|
||||
menu.findItem(R.id.share).setVisible(false);
|
||||
menu.findItem(R.id.add_to_launcher).setVisible(false);
|
||||
menu.findItem(R.id.subscribe).setVisible(false);
|
||||
menu.findItem(R.id.add_search_engine).setVisible(false);
|
||||
MenuUtils.safeSetVisible(menu, R.id.share, false);
|
||||
MenuUtils.safeSetVisible(menu, R.id.subscribe, false);
|
||||
MenuUtils.safeSetVisible(menu, R.id.add_search_engine, false);
|
||||
}
|
||||
|
||||
menu.findItem(R.id.share).setVisible(!GeckoProfile.get(getContext()).inGuestMode());
|
||||
MenuUtils.safeSetVisible(menu, R.id.share, !GeckoProfile.get(getContext()).inGuestMode());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -79,7 +79,8 @@ public class SiteIdentityPopup extends ArrowPopup {
|
||||
init();
|
||||
}
|
||||
|
||||
if (mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_LOADED) {
|
||||
if (mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_LOADED ||
|
||||
mSiteIdentity.getSecurityMode() == SecurityMode.MIXED_CONTENT_BLOCKED) {
|
||||
// Hide the identity data if there isn't valid site identity data.
|
||||
// Set some top padding on the popup content to create a of light blue
|
||||
// between the popup arrow and the mixed content notification.
|
||||
|
@ -150,12 +150,9 @@ public class ToolbarDisplayLayout extends GeckoLinearLayout
|
||||
mPrivateDomainColor = new ForegroundColorSpan(res.getColor(R.color.url_bar_domaintext_private));
|
||||
|
||||
mFavicon = (ImageButton) findViewById(R.id.favicon);
|
||||
if (Build.VERSION.SDK_INT >= 11) {
|
||||
if (Build.VERSION.SDK_INT >= 16) {
|
||||
mFavicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
}
|
||||
mFavicon.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
mFaviconSize = Math.round(res.getDimension(R.dimen.browser_toolbar_favicon_size));
|
||||
|
||||
mSiteSecurity = (ImageButton) findViewById(R.id.site_security);
|
||||
|
33
mobile/android/base/util/MenuUtils.java
Normal file
33
mobile/android/base/util/MenuUtils.java
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* 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/. */
|
||||
|
||||
package org.mozilla.gecko.util;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
public class MenuUtils {
|
||||
/*
|
||||
* This method looks for a menuitem and sets it's visible state, if
|
||||
* it exists.
|
||||
*/
|
||||
public static void safeSetVisible(Menu menu, int id, boolean visible) {
|
||||
MenuItem item = menu.findItem(id);
|
||||
if (item != null) {
|
||||
item.setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This method looks for a menuitem and sets it's enabled state, if
|
||||
* it exists.
|
||||
*/
|
||||
public static void safeSetEnabled(Menu menu, int id, boolean enabled) {
|
||||
MenuItem item = menu.findItem(id);
|
||||
if (item != null) {
|
||||
item.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
@ -240,7 +240,9 @@ function resolveGeckoURI(aURI) {
|
||||
}
|
||||
|
||||
function shouldShowProgress(url) {
|
||||
return (url != "about:home" && !url.startsWith("about:reader"));
|
||||
return (url != "about:home" &&
|
||||
url != "about:privatebrowsing" &&
|
||||
!url.startsWith("about:reader"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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>
|
||||
|
@ -178,7 +178,8 @@ function updateBanner(response) {
|
||||
text: message.text,
|
||||
icon: message.icon,
|
||||
onclick: function() {
|
||||
gChromeWin.BrowserApp.addTab(message.url);
|
||||
let parentId = gChromeWin.BrowserApp.selectedTab.id;
|
||||
gChromeWin.BrowserApp.addTab(message.url, { parentId: parentId });
|
||||
},
|
||||
onshown: function() {
|
||||
// 10% of the time, record the snippet id and a timestamp
|
||||
|
@ -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>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user