Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2014-02-07 17:36:50 -08:00
commit 3887604616
111 changed files with 2828 additions and 1954 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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,

View File

@ -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");
}
},

View File

@ -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();

View File

@ -82,16 +82,20 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
"resource:///modules/BrowserUITelemetry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
"resource:///modules/AsyncShutdown.jsm");
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
// We try to backup bookmarks at idle times, to avoid doing that at shutdown.
// Number of idle seconds before trying to backup bookmarks. 10 minutes.
const BOOKMARKS_BACKUP_IDLE_TIME = 10 * 60;
// Minimum interval in milliseconds between backups.
const BOOKMARKS_BACKUP_INTERVAL = 86400 * 1000;
// Maximum number of backups to create. Old ones will be purged.
const BOOKMARKS_BACKUP_MAX_BACKUPS = 10;
// Seconds of idle before trying to create a bookmarks backup.
const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 10 * 60;
// Minimum interval between backups. We try to not create more than one backup
// per interval.
const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
// Maximum interval between backups. If the last backup is older than these
// days we will try to create a new one more aggressively.
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 5;
// Factory object
const BrowserGlueServiceFactory = {
@ -134,7 +138,6 @@ function BrowserGlue() {
BrowserGlue.prototype = {
_saveSession: false,
_isIdleObserver: false,
_isPlacesInitObserver: false,
_isPlacesLockedObserver: false,
_isPlacesShutdownObserver: false,
@ -202,16 +205,7 @@ BrowserGlue.prototype = {
this._onQuitRequest(subject, data);
break;
case "quit-application-granted":
// This pref must be set here because SessionStore will use its value
// on quit-application.
this._setPrefToSaveSession();
try {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
getService(Ci.nsIAppStartup);
appStartup.trackStartupCrashEnd();
} catch (e) {
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
}
this._onQuitApplicationGranted();
break;
#ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
case "browser-lastwindow-close-requested":
@ -262,8 +256,7 @@ BrowserGlue.prototype = {
this._onPlacesShutdown();
break;
case "idle":
if (this._idleService.idleTime > BOOKMARKS_BACKUP_IDLE_TIME * 1000)
this._backupBookmarks();
this._backupBookmarks();
break;
case "distribution-customization-complete":
Services.obs.removeObserver(this, "distribution-customization-complete");
@ -304,7 +297,10 @@ BrowserGlue.prototype = {
}
break;
case "profile-before-change":
this._onProfileShutdown();
// Any component depending on Places should be finalized in
// _onPlacesShutdown. Any component that doesn't need to act after
// the UI has gone should be finalized in _onQuitApplicationGranted.
this._dispose();
break;
#ifdef MOZ_SERVICES_HEALTHREPORT
case "keyword-search":
@ -422,8 +418,10 @@ BrowserGlue.prototype = {
os.removeObserver(this, "weave:engine:clients:display-uri");
#endif
os.removeObserver(this, "session-save");
if (this._isIdleObserver)
this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
if (this._bookmarksBackupIdleTime) {
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
delete this._bookmarksBackupIdleTime;
}
if (this._isPlacesInitObserver)
os.removeObserver(this, "places-init-complete");
if (this._isPlacesLockedObserver)
@ -634,16 +632,24 @@ BrowserGlue.prototype = {
},
/**
* Profile shutdown handler (contains profile cleanup routines).
* All components depending on Places should be shut down in
* _onPlacesShutdown() and not here.
* Application shutdown handler.
*/
_onProfileShutdown: function BG__onProfileShutdown() {
_onQuitApplicationGranted: function () {
// This pref must be set here because SessionStore will use its value
// on quit-application.
this._setPrefToSaveSession();
try {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
appStartup.trackStartupCrashEnd();
} catch (e) {
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
}
BrowserNewTabPreloader.uninit();
webappsUI.uninit();
SignInToWebsiteUX.uninit();
webrtcUI.uninit();
this._dispose();
},
// All initial windows have opened.
@ -1060,14 +1066,18 @@ BrowserGlue.prototype = {
}
} catch(ex) {}
// This may be reused later, check for "=== undefined" to see if it has
// been populated already.
let lastBackupFile;
// If the user did not require to restore default bookmarks, or import
// from bookmarks.html, we will try to restore from JSON
if (importBookmarks && !restoreDefaultBookmarks && !importBookmarksHTML) {
// get latest JSON backup
var bookmarksBackupFile = yield PlacesBackups.getMostRecent("json");
if (bookmarksBackupFile) {
lastBackupFile = yield PlacesBackups.getMostRecentBackup("json");
if (lastBackupFile) {
// restore from JSON backup
yield BookmarkJSONUtils.importFromFile(bookmarksBackupFile, true);
yield BookmarkJSONUtils.importFromFile(lastBackupFile, true);
importBookmarks = false;
}
else {
@ -1162,10 +1172,39 @@ BrowserGlue.prototype = {
}
// Initialize bookmark archiving on idle.
// Once a day, either on idle or shutdown, bookmarks are backed up.
if (!this._isIdleObserver) {
this._idleService.addIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
this._isIdleObserver = true;
if (!this._bookmarksBackupIdleTime) {
this._bookmarksBackupIdleTime = BOOKMARKS_BACKUP_IDLE_TIME_SEC;
// If there is no backup, or the last bookmarks backup is too old, use
// a more aggressive idle observer.
if (lastBackupFile === undefined)
lastBackupFile = yield PlacesBackups.getMostRecentBackup();
if (!lastBackupFile) {
this._bookmarksBackupIdleTime /= 2;
}
else {
let lastBackupTime = PlacesBackups.getDateForFile(lastBackupFile);
let profileLastUse = Services.appinfo.replacedLockTime || Date.now();
// If there is a backup after the last profile usage date it's fine,
// regardless its age. Otherwise check how old is the last
// available backup compared to that session.
if (profileLastUse > lastBackupTime) {
let backupAge = Math.round((profileLastUse - lastBackupTime) / 86400000);
// Report the age of the last available backup.
try {
Services.telemetry
.getHistogramById("PLACES_BACKUPS_DAYSFROMLAST")
.add(backupAge);
} catch (ex) {
Components.utils.reportError("Unable to report telemetry.");
}
if (backupAge > BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS)
this._bookmarksBackupIdleTime /= 2;
}
}
this._idleService.addIdleObserver(this, this._bookmarksBackupIdleTime);
}
Services.obs.notifyObservers(null, "places-browser-init-complete", "");
@ -1174,63 +1213,34 @@ BrowserGlue.prototype = {
/**
* Places shut-down tasks
* - back up bookmarks if needed.
* - export bookmarks as HTML, if so configured.
* - finalize components depending on Places.
* - export bookmarks as HTML, if so configured.
*/
_onPlacesShutdown: function BG__onPlacesShutdown() {
this._sanitizer.onShutdown();
PageThumbs.uninit();
if (this._isIdleObserver) {
this._idleService.removeIdleObserver(this, BOOKMARKS_BACKUP_IDLE_TIME);
this._isIdleObserver = false;
if (this._bookmarksBackupIdleTime) {
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
delete this._bookmarksBackupIdleTime;
}
let waitingForBackupToComplete = true;
this._backupBookmarks().then(
function onSuccess() {
waitingForBackupToComplete = false;
},
function onFailure() {
Cu.reportError("Unable to backup bookmarks.");
waitingForBackupToComplete = false;
// Support legacy bookmarks.html format for apps that depend on that format.
try {
if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
// places-shutdown happens at profile-change-teardown, so here we
// can safely add a profile-before-change blocker.
AsyncShutdown.profileBeforeChange.addBlocker(
"Places: bookmarks.html",
() => BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks", Ci.nsIFile))
.then(null, Cu.reportError)
);
}
);
// Backup bookmarks to bookmarks.html to support apps that depend
// on the legacy format.
let waitingForHTMLExportToComplete = false;
// If this fails to get the preference value, we don't export.
if (Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML")) {
// Exceptionally, since this is a non-default setting and HTML format is
// discouraged in favor of the JSON backups, we spin the event loop on
// shutdown, to wait for the export to finish. We cannot safely spin
// the event loop on shutdown until we include a watchdog to prevent
// potential hangs (bug 518683). The asynchronous shutdown operations
// will then be handled by a shutdown service (bug 435058).
waitingForHTMLExportToComplete = true;
BookmarkHTMLUtils.exportToFile(Services.dirsvc.get("BMarks", Ci.nsIFile)).then(
function onSuccess() {
waitingForHTMLExportToComplete = false;
},
function onFailure() {
Cu.reportError("Unable to auto export html.");
waitingForHTMLExportToComplete = false;
}
);
}
// The events loop should spin at least once because waitingForBackupToComplete
// is true before checking whether backup should be made.
let thread = Services.tm.currentThread;
while (waitingForBackupToComplete || waitingForHTMLExportToComplete) {
thread.processNextEvent(true);
}
} catch (ex) {} // Do not export.
},
/**
* Backup bookmarks.
* If a backup for today doesn't exist, this creates one.
*/
_backupBookmarks: function BG__backupBookmarks() {
return Task.spawn(function() {
@ -1238,14 +1248,9 @@ BrowserGlue.prototype = {
// Should backup bookmarks if there are no backups or the maximum
// interval between backups elapsed.
if (!lastBackupFile ||
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_INTERVAL) {
let maxBackups = BOOKMARKS_BACKUP_MAX_BACKUPS;
try {
maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
}
catch(ex) { /* Use default. */ }
yield PlacesBackups.create(maxBackups); // Don't force creation.
new Date() - PlacesBackups.getDateForFile(lastBackupFile) > BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS * 86400000) {
let maxBackups = Services.prefs.getIntPref("browser.bookmarks.max_backups");
yield PlacesBackups.create(maxBackups);
}
});
},

View File

@ -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);
}
};

View File

@ -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);
});

View File

@ -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();
}

View File

@ -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"
];

View File

@ -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]

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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"),

View File

@ -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>

View File

@ -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");

View File

@ -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)

View File

@ -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);

View File

@ -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/>

View File

@ -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'");

View File

@ -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/>

View File

@ -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'");

View File

@ -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.

View File

@ -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

View File

@ -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>

View File

@ -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]

View File

@ -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>

View 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>

View File

@ -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);

View File

@ -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.

View File

@ -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>">

View File

@ -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)
{

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View 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');

View 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);
}

View File

@ -236,17 +236,25 @@ DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
heap = &bufferVal.toObject().as<ArrayBufferObject>();
if (!IsValidAsmJSHeapLength(heap->byteLength())) {
return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next valid length is 0x%x",
heap->byteLength(),
RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
ScopedJSFreePtr<char> msg(
JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
"valid length is 0x%x",
heap->byteLength(),
RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
return LinkFail(cx, msg.get());
}
// This check is sufficient without considering the size of the loaded datum because heap
// loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
if (heap->byteLength() < module.minHeapLength()) {
return LinkFail(cx, JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the largest constant heap access offset rounded up to the next valid heap size).",
heap->byteLength(), module.minHeapLength()));
ScopedJSFreePtr<char> msg(
JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the"
"largest constant heap access offset rounded up to the next valid "
"heap size).",
heap->byteLength(),
module.minHeapLength()));
return LinkFail(cx, msg.get());
}
if (!ArrayBufferObject::prepareForAsmJS(cx, heap))

View File

@ -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())

View File

@ -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*>;

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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_;

View File

@ -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_)

View File

@ -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);

View File

@ -149,7 +149,7 @@ JSScript::principals()
}
inline JSFunction *
JSScript::originalFunction() const {
JSScript::donorFunction() const {
if (!isCallsiteClone())
return nullptr;
return &enclosingScopeOrOriginalFunction_->as<JSFunction>();

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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
{

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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(),

View File

@ -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
*/

View File

@ -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
*/

View File

@ -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;

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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] =
{

View File

@ -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(

View File

@ -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,

View File

@ -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 */

View File

@ -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");

View File

@ -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,

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);

View File

@ -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">

View File

@ -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',

View File

@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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";

View File

@ -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) {
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");
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 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);

View File

@ -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());
}
});

View File

@ -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.

View File

@ -150,11 +150,8 @@ 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);
if (Build.VERSION.SDK_INT >= 16) {
mFavicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
mFaviconSize = Math.round(res.getDimension(R.dimen.browser_toolbar_favicon_size));

View 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);
}
}
}

View File

@ -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"));
}
/**

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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