mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Merge autoland to mozilla-central r=merge a=merge
This commit is contained in:
commit
978711ce7c
@ -25,6 +25,7 @@
|
||||
#include <winreg.h>
|
||||
|
||||
#include "AccessibleHypertext.h"
|
||||
#include "AccessibleHypertext2.h"
|
||||
#include "Accessible2_i.c"
|
||||
#include "Accessible2_2_i.c"
|
||||
#include "Accessible2_3_i.c"
|
||||
@ -209,8 +210,9 @@ AccessibleHandler::QueryHandlerInterface(IUnknown* aProxyUnknown, REFIID aIid,
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext) {
|
||||
RefPtr<IAccessibleHypertext> textTearoff(new AccessibleTextTearoff(this));
|
||||
if (aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext ||
|
||||
aIid == IID_IAccessibleHypertext2) {
|
||||
RefPtr<IAccessibleHypertext2> textTearoff(new AccessibleTextTearoff(this));
|
||||
textTearoff.forget(aOutInterface);
|
||||
return S_OK;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "AccessibleHandlerControl.h"
|
||||
#include "AccessibleText_i.c"
|
||||
#include "AccessibleHypertext_i.c"
|
||||
#include "AccessibleHypertext2_i.c"
|
||||
#include "Factory.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
@ -38,13 +39,14 @@ AccessibleTextTearoff::ResolveAccHypertext()
|
||||
return E_UNEXPECTED;
|
||||
}
|
||||
|
||||
return proxy->QueryInterface(IID_IAccessibleHypertext,
|
||||
return proxy->QueryInterface(IID_IAccessibleHypertext2,
|
||||
getter_AddRefs(mAccHypertextProxy));
|
||||
}
|
||||
|
||||
IMPL_IUNKNOWN_QUERY_HEAD(AccessibleTextTearoff)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleText)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleHypertext)
|
||||
IMPL_IUNKNOWN_QUERY_IFACE(IAccessibleHypertext2)
|
||||
IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler)
|
||||
|
||||
HRESULT
|
||||
@ -338,6 +340,17 @@ AccessibleTextTearoff::get_hyperlinkIndex(long charIndex, long *hyperlinkIndex)
|
||||
return mAccHypertextProxy->get_hyperlinkIndex(charIndex, hyperlinkIndex);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleTextTearoff::get_hyperlinks(IAccessibleHyperlink*** hyperlinks,
|
||||
long* nHyperlinks)
|
||||
{
|
||||
HRESULT hr = ResolveAccHypertext();
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return mAccHypertextProxy->get_hyperlinks(hyperlinks, nHyperlinks);
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
@ -12,14 +12,14 @@
|
||||
#define mozilla_a11y_AccessibleTextTearoff_h
|
||||
|
||||
#include "AccessibleHandler.h"
|
||||
#include "AccessibleHypertext.h"
|
||||
#include "AccessibleHypertext2.h"
|
||||
#include "IUnknownImpl.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
class AccessibleTextTearoff final : public IAccessibleHypertext
|
||||
class AccessibleTextTearoff final : public IAccessibleHypertext2
|
||||
{
|
||||
public:
|
||||
explicit AccessibleTextTearoff(AccessibleHandler* aHandler);
|
||||
@ -72,12 +72,16 @@ public:
|
||||
IAccessibleHyperlink **hyperlink) override;
|
||||
STDMETHODIMP get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) override;
|
||||
|
||||
// IAccessibleHypertext2
|
||||
STDMETHODIMP get_hyperlinks(IAccessibleHyperlink*** hyperlinks,
|
||||
long* nHyperlinks) override;
|
||||
|
||||
private:
|
||||
~AccessibleTextTearoff() = default;
|
||||
HRESULT ResolveAccHypertext();
|
||||
|
||||
RefPtr<AccessibleHandler> mHandler;
|
||||
RefPtr<IAccessibleHypertext> mAccHypertextProxy;
|
||||
RefPtr<IAccessibleHypertext2> mAccHypertextProxy;
|
||||
};
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -654,6 +654,7 @@ pref("mousewheel.with_win.action", 1);
|
||||
|
||||
pref("browser.xul.error_pages.enabled", true);
|
||||
pref("browser.xul.error_pages.expert_bad_cert", false);
|
||||
pref("browser.xul.error_pages.show_safe_browsing_details_on_load", false);
|
||||
|
||||
// Enable captive portal detection.
|
||||
pref("network.captive-portal-service.enabled", true);
|
||||
|
@ -199,6 +199,13 @@ var AboutBlockedSiteListener = {
|
||||
doc.getElementById("firefox_support").setAttribute("href",
|
||||
"https://support.mozilla.org/kb/how-does-phishing-and-malware-protection-work");
|
||||
|
||||
// Show safe browsing details on load if the pref is set to true.
|
||||
let showDetails = Services.prefs.getBoolPref("browser.xul.error_pages.show_safe_browsing_details_on_load");
|
||||
if (showDetails) {
|
||||
let details = content.document.getElementById("errorDescriptionContainer");
|
||||
details.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
// Set safe browsing advisory link.
|
||||
let advisoryUrl = Services.prefs.getCharPref(
|
||||
"browser.safebrowsing.provider." + provider + ".advisoryURL", "");
|
||||
|
@ -60,10 +60,6 @@ var whitelist = [
|
||||
{file: "chrome://global/locale/printPreviewProgress.dtd",
|
||||
platforms: ["macosx"]},
|
||||
{file: "chrome://global/locale/printProgress.dtd", platforms: ["macosx"]},
|
||||
{file: "chrome://global/locale/printdialog.dtd",
|
||||
platforms: ["macosx", "win"]},
|
||||
{file: "chrome://global/locale/printjoboptions.dtd",
|
||||
platforms: ["macosx", "win"]},
|
||||
|
||||
// devtools/client/inspector/bin/dev-server.js
|
||||
{file: "chrome://devtools/content/inspector/markup/markup.xhtml",
|
||||
|
@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
@ -49,37 +49,39 @@ this.SiteDataManager = {
|
||||
this._cancelGetQuotaUsage();
|
||||
this._getQuotaUsagePromise = new Promise(resolve => {
|
||||
let onUsageResult = request => {
|
||||
let items = request.result;
|
||||
for (let item of items) {
|
||||
if (!item.persisted && item.usage <= 0) {
|
||||
// An non-persistent-storage site with 0 byte quota usage is redundant for us so skip it.
|
||||
continue;
|
||||
}
|
||||
let principal =
|
||||
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
|
||||
let uri = principal.URI;
|
||||
if (uri.scheme == "http" || uri.scheme == "https") {
|
||||
let site = this._sites.get(uri.host);
|
||||
if (!site) {
|
||||
site = {
|
||||
persisted: false,
|
||||
quotaUsage: 0,
|
||||
principals: [],
|
||||
appCacheList: [],
|
||||
};
|
||||
if (request.resultCode == Cr.NS_OK) {
|
||||
let items = request.result;
|
||||
for (let item of items) {
|
||||
if (!item.persisted && item.usage <= 0) {
|
||||
// An non-persistent-storage site with 0 byte quota usage is redundant for us so skip it.
|
||||
continue;
|
||||
}
|
||||
// Assume 3 sites:
|
||||
// - Site A (not persisted): https://www.foo.com
|
||||
// - Site B (not persisted): https://www.foo.com^userContextId=2
|
||||
// - Site C (persisted): https://www.foo.com:1234
|
||||
// Although only C is persisted, grouping by host, as a result,
|
||||
// we still mark as persisted here under this host group.
|
||||
if (item.persisted) {
|
||||
site.persisted = true;
|
||||
let principal =
|
||||
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin);
|
||||
let uri = principal.URI;
|
||||
if (uri.scheme == "http" || uri.scheme == "https") {
|
||||
let site = this._sites.get(uri.host);
|
||||
if (!site) {
|
||||
site = {
|
||||
persisted: false,
|
||||
quotaUsage: 0,
|
||||
principals: [],
|
||||
appCacheList: [],
|
||||
};
|
||||
}
|
||||
// Assume 3 sites:
|
||||
// - Site A (not persisted): https://www.foo.com
|
||||
// - Site B (not persisted): https://www.foo.com^userContextId=2
|
||||
// - Site C (persisted): https://www.foo.com:1234
|
||||
// Although only C is persisted, grouping by host, as a result,
|
||||
// we still mark as persisted here under this host group.
|
||||
if (item.persisted) {
|
||||
site.persisted = true;
|
||||
}
|
||||
site.principals.push(principal);
|
||||
site.quotaUsage += item.usage;
|
||||
this._sites.set(uri.host, site);
|
||||
}
|
||||
site.principals.push(principal);
|
||||
site.quotaUsage += item.usage;
|
||||
this._sites.set(uri.host, site);
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
@ -222,37 +224,54 @@ this.SiteDataManager = {
|
||||
}
|
||||
},
|
||||
|
||||
_removeServiceWorkers(site) {
|
||||
_unregisterServiceWorker(serviceWorker) {
|
||||
return new Promise(resolve => {
|
||||
let unregisterCallback = {
|
||||
unregisterSucceeded: resolve,
|
||||
unregisterFailed: resolve, // We don't care about failures.
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIServiceWorkerUnregisterCallback])
|
||||
};
|
||||
serviceWorkerManager.propagateUnregister(serviceWorker.principal, unregisterCallback, serviceWorker.scope);
|
||||
});
|
||||
},
|
||||
|
||||
_removeServiceWorkersForSites(sites) {
|
||||
let promises = [];
|
||||
let targetHosts = sites.map(s => s.principals[0].URI.host);
|
||||
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
|
||||
for (let i = 0; i < serviceWorkers.length; i++) {
|
||||
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
|
||||
for (let principal of site.principals) {
|
||||
if (sw.principal.equals(principal)) {
|
||||
serviceWorkerManager.removeAndPropagate(sw.principal.URI.host);
|
||||
break;
|
||||
}
|
||||
// Sites are grouped and removed by host so we unregister service workers by the same host as well
|
||||
if (targetHosts.includes(sw.principal.URI.host)) {
|
||||
promises.push(this._unregisterServiceWorker(sw));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
remove(hosts) {
|
||||
let promises = [];
|
||||
let unknownHost = "";
|
||||
let targetSites = [];
|
||||
for (let host of hosts) {
|
||||
let site = this._sites.get(host);
|
||||
if (site) {
|
||||
this._removePermission(site);
|
||||
this._removeAppCache(site);
|
||||
this._removeCookie(site);
|
||||
this._removeServiceWorkers(site);
|
||||
promises.push(this._removeQuotaUsage(site));
|
||||
targetSites.push(site);
|
||||
} else {
|
||||
unknownHost = host;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (promises.length > 0) {
|
||||
Promise.all(promises).then(() => this.updateSites());
|
||||
|
||||
if (targetSites.length > 0) {
|
||||
this._removeServiceWorkersForSites(targetSites)
|
||||
.then(() => {
|
||||
let promises = targetSites.map(s => this._removeQuotaUsage(s));
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(() => this.updateSites());
|
||||
}
|
||||
if (unknownHost) {
|
||||
throw `SiteDataManager: removing unknown site of ${unknownHost}`;
|
||||
@ -265,12 +284,13 @@ this.SiteDataManager = {
|
||||
OfflineAppCacheHelper.clear();
|
||||
|
||||
// Iterate through the service workers and remove them.
|
||||
let promises = [];
|
||||
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
|
||||
for (let i = 0; i < serviceWorkers.length; i++) {
|
||||
let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo);
|
||||
let host = sw.principal.URI.host;
|
||||
serviceWorkerManager.removeAndPropagate(host);
|
||||
promises.push(this._unregisterServiceWorker(sw));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
|
||||
// Refresh sites using quota usage again.
|
||||
// This is for the case:
|
||||
@ -283,7 +303,7 @@ this.SiteDataManager = {
|
||||
// because that would clear browser data as well too,
|
||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1312361#c9
|
||||
await this._getQuotaUsage();
|
||||
let promises = [];
|
||||
promises = [];
|
||||
for (let site of this._sites.values()) {
|
||||
this._removePermission(site);
|
||||
promises.push(this._removeQuotaUsage(site));
|
||||
|
@ -112,37 +112,16 @@ var gBlocklistManager = {
|
||||
}
|
||||
|
||||
if (activeList !== selected.id) {
|
||||
const Cc = Components.classes, Ci = Components.interfaces;
|
||||
let msg = this._bundle.getFormattedString("blocklistChangeRequiresRestart",
|
||||
[this._brandShortName]);
|
||||
let title = this._bundle.getFormattedString("shouldRestartTitle",
|
||||
[this._brandShortName]);
|
||||
let shouldProceed = Services.prompt.confirm(window, title, msg);
|
||||
if (shouldProceed) {
|
||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
||||
"restart");
|
||||
shouldProceed = !cancelQuit.data;
|
||||
|
||||
if (shouldProceed) {
|
||||
let trackingTable = Services.prefs.getCharPref(TRACKING_TABLE_PREF);
|
||||
if (selected.id != CONTENT_LIST_ID) {
|
||||
trackingTable = trackingTable.replace("," + CONTENT_LIST_ID + TRACK_SUFFIX, "");
|
||||
} else {
|
||||
trackingTable += "," + CONTENT_LIST_ID + TRACK_SUFFIX;
|
||||
}
|
||||
Services.prefs.setCharPref(TRACKING_TABLE_PREF, trackingTable);
|
||||
Services.prefs.setCharPref(UPDATE_TIME_PREF, 42);
|
||||
|
||||
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit |
|
||||
Ci.nsIAppStartup.eRestart);
|
||||
}
|
||||
let trackingTable = Services.prefs.getCharPref(TRACKING_TABLE_PREF);
|
||||
if (selected.id != CONTENT_LIST_ID) {
|
||||
trackingTable = trackingTable.replace("," + CONTENT_LIST_ID + TRACK_SUFFIX, "");
|
||||
} else {
|
||||
trackingTable += "," + CONTENT_LIST_ID + TRACK_SUFFIX;
|
||||
}
|
||||
|
||||
// Don't close the dialog in case we didn't quit.
|
||||
return;
|
||||
Services.prefs.setCharPref(TRACKING_TABLE_PREF, trackingTable);
|
||||
Services.prefs.setCharPref(UPDATE_TIME_PREF, 42);
|
||||
}
|
||||
|
||||
window.close();
|
||||
},
|
||||
|
||||
|
@ -3,6 +3,8 @@ support-files =
|
||||
head.js
|
||||
privacypane_tests_perwindow.js
|
||||
site_data_test.html
|
||||
service_worker_test.html
|
||||
service_worker_test.js
|
||||
addons/set_homepage.xpi
|
||||
addons/set_newtab.xpi
|
||||
offline/offline.html
|
||||
|
@ -15,6 +15,7 @@ const TEST_QUOTA_USAGE_URL = TEST_QUOTA_USAGE_ORIGIN + "/browser/browser/compone
|
||||
const TEST_OFFLINE_HOST = "example.org";
|
||||
const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
|
||||
const TEST_OFFLINE_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/offline/offline.html";
|
||||
const TEST_SERVICE_WORKER_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/service_worker_test.html";
|
||||
const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul";
|
||||
|
||||
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||
@ -22,6 +23,8 @@ const { DownloadUtils } = Cu.import("resource://gre/modules/DownloadUtils.jsm",
|
||||
const { SiteDataManager } = Cu.import("resource:///modules/SiteDataManager.jsm", {});
|
||||
const { OfflineAppCacheHelper } = Cu.import("resource:///modules/offlineAppCache.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager", "@mozilla.org/serviceworkers/manager;1", "nsIServiceWorkerManager");
|
||||
|
||||
const mockOfflineAppCacheHelper = {
|
||||
clear: null,
|
||||
|
||||
@ -87,6 +90,40 @@ function promiseCookiesCleared() {
|
||||
});
|
||||
}
|
||||
|
||||
async function loadServiceWorkerTestPage(url) {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
await BrowserTestUtils.waitForCondition(() => {
|
||||
return ContentTask.spawn(tab.linkedBrowser, {}, () =>
|
||||
content.document.body.getAttribute("data-test-service-worker-registered") === "true");
|
||||
}, `Fail to load service worker test ${url}`);
|
||||
await BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
function promiseServiceWorkerRegisteredFor(url) {
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
try {
|
||||
let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(url);
|
||||
let sw = serviceWorkerManager.getRegistrationByPrincipal(principal, principal.URI.spec);
|
||||
if (sw) {
|
||||
ok(true, `Found the service worker registered for ${url}`);
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}, `Should register service worker for ${url}`);
|
||||
}
|
||||
|
||||
function promiseServiceWorkersCleared() {
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
let serviceWorkers = serviceWorkerManager.getAllRegistrations();
|
||||
if (serviceWorkers.length == 0) {
|
||||
ok(true, "Cleared all service workers");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, "Should clear all service workers");
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
delete window.sinon;
|
||||
mockOfflineAppCacheHelper.unregister();
|
||||
@ -250,120 +287,55 @@ add_task(async function() {
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Test sorting
|
||||
// Test clearing service wroker through the "Clear All" button
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
mockSiteDataManager.register(SiteDataManager);
|
||||
mockSiteDataManager.fakeSites = [
|
||||
{
|
||||
usage: 1024,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
|
||||
persisted: true
|
||||
},
|
||||
{
|
||||
usage: 1024 * 2,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("https://books.foo.com"),
|
||||
persisted: false
|
||||
},
|
||||
{
|
||||
usage: 1024 * 3,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
|
||||
persisted: true
|
||||
},
|
||||
];
|
||||
|
||||
let updatePromise = promiseSiteDataManagerSitesUpdated();
|
||||
// Register a test service
|
||||
await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL);
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
|
||||
// Test the initial states
|
||||
await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL);
|
||||
// Click the "Clear All" button
|
||||
let doc = gBrowser.selectedBrowser.contentDocument;
|
||||
let clearBtn = doc.getElementById("clearSiteDataButton");
|
||||
let acceptPromise = promiseAlertDialogOpen("accept");
|
||||
let updatePromise = promiseSiteDataManagerSitesUpdated();
|
||||
clearBtn.doCommand();
|
||||
await acceptPromise;
|
||||
await updatePromise;
|
||||
await openSiteDataSettingsDialog();
|
||||
|
||||
let dialog = content.gSubDialog._topDialog;
|
||||
let dialogFrame = dialog._frame;
|
||||
let frameDoc = dialogFrame.contentDocument;
|
||||
let hostCol = frameDoc.getElementById("hostCol");
|
||||
let usageCol = frameDoc.getElementById("usageCol");
|
||||
let statusCol = frameDoc.getElementById("statusCol");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
|
||||
// Test default sorting
|
||||
assertSortByUsage("descending");
|
||||
|
||||
// Test sorting on the usage column
|
||||
usageCol.click();
|
||||
assertSortByUsage("ascending");
|
||||
usageCol.click();
|
||||
assertSortByUsage("descending");
|
||||
|
||||
// Test sorting on the host column
|
||||
hostCol.click();
|
||||
assertSortByHost("ascending");
|
||||
hostCol.click();
|
||||
assertSortByHost("descending");
|
||||
|
||||
// Test sorting on the permission status column
|
||||
statusCol.click();
|
||||
assertSortByStatus("ascending");
|
||||
statusCol.click();
|
||||
assertSortByStatus("descending");
|
||||
|
||||
mockSiteDataManager.unregister();
|
||||
await promiseServiceWorkersCleared();
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Test clearing service wroker through the settings panel
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
// Register a test service worker
|
||||
await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL);
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
|
||||
// Test the initial states
|
||||
await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL);
|
||||
// Open the Site Data Settings panel and remove the site
|
||||
await openSiteDataSettingsDialog();
|
||||
let acceptRemovePromise = promiseAlertDialogOpen("accept");
|
||||
let updatePromise = promiseSiteDataManagerSitesUpdated();
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, { TEST_OFFLINE_HOST }, args => {
|
||||
let host = args.TEST_OFFLINE_HOST;
|
||||
let frameDoc = content.gSubDialog._topDialog._frame.contentDocument;
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
|
||||
if (site) {
|
||||
let removeBtn = frameDoc.getElementById("removeSelected");
|
||||
let saveBtn = frameDoc.getElementById("save");
|
||||
site.click();
|
||||
removeBtn.doCommand();
|
||||
saveBtn.doCommand();
|
||||
} else {
|
||||
ok(false, `Should have one site of ${host}`);
|
||||
}
|
||||
});
|
||||
await acceptRemovePromise;
|
||||
await updatePromise;
|
||||
await promiseServiceWorkersCleared();
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
function assertSortByHost(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let result = aHost.localeCompare(bHost);
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by host");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by host");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByStatus(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let a = findSiteByHost(aHost);
|
||||
let b = findSiteByHost(bHost);
|
||||
let result = 0;
|
||||
if (a.persisted && !b.persisted) {
|
||||
result = 1;
|
||||
} else if (!a.persisted && b.persisted) {
|
||||
result = -1;
|
||||
}
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by permission status");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by permission status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByUsage(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let a = findSiteByHost(aHost);
|
||||
let b = findSiteByHost(bHost);
|
||||
let result = a.usage - b.usage;
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSiteByHost(host) {
|
||||
return mockSiteDataManager.fakeSites.find(site => site.principal.URI.host == host);
|
||||
}
|
||||
});
|
||||
|
@ -106,3 +106,121 @@ add_task(async function() {
|
||||
mockSiteDataManager.unregister();
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
// Test sorting
|
||||
add_task(async function() {
|
||||
await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
|
||||
mockSiteDataManager.register(SiteDataManager);
|
||||
mockSiteDataManager.fakeSites = [
|
||||
{
|
||||
usage: 1024,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("https://account.xyz.com"),
|
||||
persisted: true
|
||||
},
|
||||
{
|
||||
usage: 1024 * 2,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("https://books.foo.com"),
|
||||
persisted: false
|
||||
},
|
||||
{
|
||||
usage: 1024 * 3,
|
||||
principal: Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin("http://cinema.bar.com"),
|
||||
persisted: true
|
||||
},
|
||||
];
|
||||
|
||||
let updatePromise = promiseSiteDataManagerSitesUpdated();
|
||||
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
|
||||
await updatePromise;
|
||||
await openSiteDataSettingsDialog();
|
||||
|
||||
let dialog = content.gSubDialog._topDialog;
|
||||
let dialogFrame = dialog._frame;
|
||||
let frameDoc = dialogFrame.contentDocument;
|
||||
let hostCol = frameDoc.getElementById("hostCol");
|
||||
let usageCol = frameDoc.getElementById("usageCol");
|
||||
let statusCol = frameDoc.getElementById("statusCol");
|
||||
let sitesList = frameDoc.getElementById("sitesList");
|
||||
|
||||
// Test default sorting
|
||||
assertSortByUsage("descending");
|
||||
|
||||
// Test sorting on the usage column
|
||||
usageCol.click();
|
||||
assertSortByUsage("ascending");
|
||||
usageCol.click();
|
||||
assertSortByUsage("descending");
|
||||
|
||||
// Test sorting on the host column
|
||||
hostCol.click();
|
||||
assertSortByHost("ascending");
|
||||
hostCol.click();
|
||||
assertSortByHost("descending");
|
||||
|
||||
// Test sorting on the permission status column
|
||||
statusCol.click();
|
||||
assertSortByStatus("ascending");
|
||||
statusCol.click();
|
||||
assertSortByStatus("descending");
|
||||
|
||||
mockSiteDataManager.unregister();
|
||||
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
function assertSortByHost(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let result = aHost.localeCompare(bHost);
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by host");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by host");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByStatus(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let a = findSiteByHost(aHost);
|
||||
let b = findSiteByHost(bHost);
|
||||
let result = 0;
|
||||
if (a.persisted && !b.persisted) {
|
||||
result = 1;
|
||||
} else if (!a.persisted && b.persisted) {
|
||||
result = -1;
|
||||
}
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by permission status");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by permission status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertSortByUsage(order) {
|
||||
let siteItems = sitesList.getElementsByTagName("richlistitem");
|
||||
for (let i = 0; i < siteItems.length - 1; ++i) {
|
||||
let aHost = siteItems[i].getAttribute("host");
|
||||
let bHost = siteItems[i + 1].getAttribute("host");
|
||||
let a = findSiteByHost(aHost);
|
||||
let b = findSiteByHost(bHost);
|
||||
let result = a.usage - b.usage;
|
||||
if (order == "ascending") {
|
||||
Assert.lessOrEqual(result, 0, "Should sort sites in the ascending order by usage");
|
||||
} else {
|
||||
Assert.greaterOrEqual(result, 0, "Should sort sites in the descending order by usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findSiteByHost(host) {
|
||||
return mockSiteDataManager.fakeSites.find(site => site.principal.URI.host == host);
|
||||
}
|
||||
});
|
||||
|
@ -254,7 +254,7 @@ const mockSiteDataManager = {
|
||||
usage: site.usage,
|
||||
persisted: site.persisted
|
||||
}));
|
||||
onUsageResult({ result });
|
||||
onUsageResult({ result, resultCode: Components.results.NS_OK });
|
||||
},
|
||||
|
||||
_removeQuotaUsage(site) {
|
||||
|
19
browser/components/preferences/in-content/tests/service_worker_test.html
Executable file
19
browser/components/preferences/in-content/tests/service_worker_test.html
Executable file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Cache-Control" content="public" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
|
||||
|
||||
<title>Service Worker Test</title>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Service Worker Test</h1>
|
||||
<script type="text/javascript">
|
||||
navigator.serviceWorker.register("service_worker_test.js")
|
||||
.then(regis => document.body.setAttribute("data-test-service-worker-registered", "true"));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
// empty worker, always succeed!
|
@ -372,11 +372,11 @@ FormAutofillParent.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.profileStorage.addresses.mergeIfPossible(address.guid, address.record)) {
|
||||
if (!this.profileStorage.addresses.mergeIfPossible(address.guid, address.record, true)) {
|
||||
this._recordFormFillingTime("address", "autofill-update", timeStartedFillingMS);
|
||||
|
||||
FormAutofillDoorhanger.show(target, "update").then((state) => {
|
||||
let changedGUIDs = this.profileStorage.addresses.mergeToStorage(address.record);
|
||||
let changedGUIDs = this.profileStorage.addresses.mergeToStorage(address.record, true);
|
||||
switch (state) {
|
||||
case "create":
|
||||
if (!changedGUIDs.length) {
|
||||
|
@ -1153,6 +1153,27 @@ class AutofillRecords {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the record if storage has multiple mergeable records.
|
||||
* @param {Object} targetRecord
|
||||
* The record for merge.
|
||||
* @param {boolean} [strict = false]
|
||||
* In strict merge mode, we'll treat the subset record with empty field
|
||||
* as unable to be merged, but mergeable if in non-strict mode.
|
||||
* @returns {Array.<string>}
|
||||
* Return an array of the merged GUID string.
|
||||
*/
|
||||
mergeToStorage(targetRecord, strict = false) {
|
||||
let mergedGUIDs = [];
|
||||
for (let record of this.data) {
|
||||
if (!record.deleted && this.mergeIfPossible(record.guid, targetRecord, strict)) {
|
||||
mergedGUIDs.push(record.guid);
|
||||
}
|
||||
}
|
||||
this.log.debug("Existing records matching and merging count is", mergedGUIDs.length);
|
||||
return mergedGUIDs;
|
||||
}
|
||||
|
||||
// A test-only helper.
|
||||
_nukeAllRecords() {
|
||||
this._store.data[this._collectionName] = [];
|
||||
@ -1173,10 +1194,7 @@ class AutofillRecords {
|
||||
_normalizeFields(record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
mergeIfPossible(guid, record) {}
|
||||
|
||||
// An interface to be inherited.
|
||||
mergeToStorage(targetRecord) {}
|
||||
mergeIfPossible(guid, record, strict) {}
|
||||
}
|
||||
|
||||
class Addresses extends AutofillRecords {
|
||||
@ -1371,10 +1389,13 @@ class Addresses extends AutofillRecords {
|
||||
* Indicates which address to merge.
|
||||
* @param {Object} address
|
||||
* The new address used to merge into the old one.
|
||||
* @param {boolean} strict
|
||||
* In strict merge mode, we'll treat the subset record with empty field
|
||||
* as unable to be merged, but mergeable if in non-strict mode.
|
||||
* @returns {boolean}
|
||||
* Return true if address is merged into target with specific guid or false if not.
|
||||
*/
|
||||
mergeIfPossible(guid, address) {
|
||||
mergeIfPossible(guid, address, strict) {
|
||||
this.log.debug("mergeIfPossible:", guid, address);
|
||||
|
||||
let addressFound = this._findByGUID(guid);
|
||||
@ -1382,7 +1403,7 @@ class Addresses extends AutofillRecords {
|
||||
throw new Error("No matching address.");
|
||||
}
|
||||
|
||||
let addressToMerge = this._clone(address);
|
||||
let addressToMerge = strict ? this._clone(address) : this._cloneAndCleanUp(address);
|
||||
this._normalizeRecord(addressToMerge);
|
||||
let hasMatchingField = false;
|
||||
|
||||
@ -1417,35 +1438,26 @@ class Addresses extends AutofillRecords {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Early return if the data is the same.
|
||||
let exactlyMatch = this.VALID_FIELDS.every((field) =>
|
||||
addressFound[field] === addressToMerge[field]
|
||||
);
|
||||
if (exactlyMatch) {
|
||||
// Early return if the data is the same or subset.
|
||||
let noNeedToUpdate = this.VALID_FIELDS.every((field) => {
|
||||
// When addressFound doesn't contain a field, it's unnecessary to update
|
||||
// if the same field in addressToMerge is omitted or an empty string.
|
||||
if (addressFound[field] === undefined) {
|
||||
return !addressToMerge[field];
|
||||
}
|
||||
|
||||
// When addressFound contains a field, it's unnecessary to update if
|
||||
// the same field in addressToMerge is omitted or a duplicate.
|
||||
return (addressToMerge[field] === undefined) ||
|
||||
(addressFound[field] === addressToMerge[field]);
|
||||
});
|
||||
if (noNeedToUpdate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.update(guid, addressToMerge, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the address if storage has multiple mergeable records.
|
||||
* @param {Object} targetAddress
|
||||
* The address for merge.
|
||||
* @returns {Array.<string>}
|
||||
* Return an array of the merged GUID string.
|
||||
*/
|
||||
mergeToStorage(targetAddress) {
|
||||
let mergedGUIDs = [];
|
||||
for (let address of this.data) {
|
||||
if (!address.deleted && this.mergeIfPossible(address.guid, targetAddress)) {
|
||||
mergedGUIDs.push(address.guid);
|
||||
}
|
||||
}
|
||||
this.log.debug("Existing records matching and merging count is", mergedGUIDs.length);
|
||||
return mergedGUIDs;
|
||||
}
|
||||
}
|
||||
|
||||
class CreditCards extends AutofillRecords {
|
||||
|
@ -119,6 +119,24 @@ add_task(async function check_storage_after_form_submitted() {
|
||||
ok(matching, "Updated address merged as expected");
|
||||
});
|
||||
|
||||
// Submit a subset address manually.
|
||||
add_task(async function submit_subset_manually() {
|
||||
document.querySelector("form").reset();
|
||||
for (let key in TEST_ADDRESSES[0]) {
|
||||
await setInput("#" + key, TEST_ADDRESSES[0][key]);
|
||||
}
|
||||
|
||||
// Set organization field to empty
|
||||
await setInput("#organization", "");
|
||||
clickOnElement("input[type=submit]");
|
||||
|
||||
let expectedAddresses = TEST_ADDRESSES.slice(0);
|
||||
|
||||
await sleep(1000);
|
||||
let matching = await checkAddresses(expectedAddresses);
|
||||
ok(matching, "The storage is still the same after submitting a subset");
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
@ -71,7 +71,7 @@ const MERGE_TESTCASES = [
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Merge a subset",
|
||||
description: "Loose merge a subset",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
@ -89,6 +89,29 @@ const MERGE_TESTCASES = [
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
noNeedToUpdate: true,
|
||||
},
|
||||
{
|
||||
description: "Strict merge a subset without empty string",
|
||||
addressInStorage: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
addressToMerge: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "+16509030800",
|
||||
},
|
||||
expectedAddress: {
|
||||
"given-name": "Timothy",
|
||||
"street-address": "331 E. Evelyn Avenue",
|
||||
"tel": "+16509030800",
|
||||
country: "US",
|
||||
},
|
||||
strict: true,
|
||||
noNeedToUpdate: true,
|
||||
},
|
||||
{
|
||||
description: "Merge an address with partial overlaps",
|
||||
@ -444,16 +467,27 @@ MERGE_TESTCASES.forEach((testcase) => {
|
||||
profileStorage.addresses.pullSyncChanges();
|
||||
do_check_eq(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
|
||||
Assert.ok(profileStorage.addresses.mergeIfPossible(guid, testcase.addressToMerge));
|
||||
await onMerged;
|
||||
Assert.ok(profileStorage.addresses.mergeIfPossible(guid,
|
||||
testcase.addressToMerge,
|
||||
testcase.strict));
|
||||
if (!testcase.noNeedToUpdate) {
|
||||
await onMerged;
|
||||
}
|
||||
|
||||
addresses = profileStorage.addresses.getAll();
|
||||
Assert.equal(addresses.length, 1);
|
||||
Assert.notEqual(addresses[0].timeLastModified, timeLastModified);
|
||||
do_check_record_matches(addresses[0], testcase.expectedAddress);
|
||||
if (testcase.noNeedToUpdate) {
|
||||
Assert.equal(addresses[0].timeLastModified, timeLastModified);
|
||||
|
||||
// Record merging should bump the change counter.
|
||||
do_check_eq(getSyncChangeCounter(profileStorage.addresses, guid), 2);
|
||||
// No need to bump the change counter if the data is unchanged.
|
||||
do_check_eq(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
} else {
|
||||
Assert.notEqual(addresses[0].timeLastModified, timeLastModified);
|
||||
|
||||
// Record merging should bump the change counter.
|
||||
do_check_eq(getSyncChangeCounter(profileStorage.addresses, guid), 2);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -492,6 +526,11 @@ add_task(async function test_merge_unable_merge() {
|
||||
// Unable to merge because no overlap
|
||||
do_check_eq(profileStorage.addresses.mergeIfPossible(guid, TEST_ADDRESS_4), false);
|
||||
|
||||
// Unable to strict merge because subset with empty string
|
||||
let subset = Object.assign({}, TEST_ADDRESS_1);
|
||||
subset.organization = "";
|
||||
do_check_eq(profileStorage.addresses.mergeIfPossible(guid, subset, true), false);
|
||||
|
||||
// Shouldn't bump the change counter
|
||||
do_check_eq(getSyncChangeCounter(profileStorage.addresses, guid), 1);
|
||||
});
|
||||
@ -507,3 +546,13 @@ add_task(async function test_mergeToStorage() {
|
||||
do_check_eq(profileStorage.addresses.getAll()[1].email, anotherAddress.email);
|
||||
do_check_eq(profileStorage.addresses.getAll()[2].email, anotherAddress.email);
|
||||
});
|
||||
|
||||
add_task(async function test_mergeToStorage_strict() {
|
||||
let profileStorage = await initProfileStorage(TEST_STORE_FILE_NAME,
|
||||
[TEST_ADDRESS_1, TEST_ADDRESS_2]);
|
||||
// Try to merge a subset with empty string
|
||||
let anotherAddress = profileStorage.addresses._clone(TEST_ADDRESS_1);
|
||||
anotherAddress.email = "";
|
||||
do_check_eq(profileStorage.addresses.mergeToStorage(anotherAddress, true).length, 0);
|
||||
do_check_eq(profileStorage.addresses.getAll()[0].email, TEST_ADDRESS_1.email);
|
||||
});
|
||||
|
@ -919,4 +919,4 @@ aboutDialog.architecture.thirtyTwoBit = 32-bit
|
||||
# LOCALIZATION NOTE (certImminentDistrust.message):
|
||||
# Shown in the browser console when visiting a website that is trusted today,
|
||||
# but won't be in the future unless the site operator makes a change.
|
||||
certImminentDistrust.message = The security certificate in use on this web site will no longer be trusted in a future release of Firefox. For more information, visit https://wiki.mozilla.org/CA/Upcoming_Distrust_Actions
|
||||
certImminentDistrust.message = The security certificate in use on this website will no longer be trusted in a future release. For more information, visit https://wiki.mozilla.org/CA/Upcoming_Distrust_Actions
|
@ -64,8 +64,6 @@ mozstdName=Disconnect.me basic protection (Recommended).
|
||||
mozstdDesc=Allows some trackers so websites function properly.
|
||||
mozfullName=Disconnect.me strict protection.
|
||||
mozfullDesc2=Blocks known trackers. Some websites may not function properly.
|
||||
# LOCALIZATION NOTE (blocklistChangeRequiresRestart): %S = brandShortName
|
||||
blocklistChangeRequiresRestart=%S must restart to change block lists.
|
||||
|
||||
#### Master Password
|
||||
|
||||
|
@ -56,7 +56,6 @@ class RequestListContent extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setScalingStyles = this.setScalingStyles.bind(this);
|
||||
this.isScrolledToBottom = this.isScrolledToBottom.bind(this);
|
||||
this.onHover = this.onHover.bind(this);
|
||||
this.onScroll = this.onScroll.bind(this);
|
||||
@ -77,9 +76,6 @@ class RequestListContent extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Set the CSS variables for waterfall scaling
|
||||
this.setScalingStyles();
|
||||
|
||||
// Install event handler for displaying a tooltip
|
||||
this.tooltip.startTogglingOnHover(this.refs.contentEl, this.onHover, {
|
||||
toggleDelay: REQUESTS_TOOLTIP_TOGGLE_DELAY,
|
||||
@ -98,9 +94,6 @@ class RequestListContent extends Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
// Update the CSS variables for waterfall scaling after props change
|
||||
this.setScalingStyles(prevProps);
|
||||
|
||||
let node = this.refs.contentEl;
|
||||
// Keep the list scrolled to bottom if a new row was added
|
||||
if (this.shouldScrollBottom && node.scrollTop !== MAX_SCROLL_HEIGHT) {
|
||||
@ -116,26 +109,6 @@ class RequestListContent extends Component {
|
||||
this.tooltip.stopTogglingOnHover();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CSS variables for waterfall scaling. If React supported setting CSS
|
||||
* variables as part of the "style" property of a DOM element, we would use that.
|
||||
*
|
||||
* However, React doesn't support this, so we need to use a hack and update the
|
||||
* DOM element directly: https://github.com/facebook/react/issues/6411
|
||||
*/
|
||||
setScalingStyles(prevProps) {
|
||||
const { scale } = this.props;
|
||||
if (prevProps && prevProps.scale === scale) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { style } = this.refs.contentEl;
|
||||
style.removeProperty("--timings-scale");
|
||||
style.removeProperty("--timings-rev-scale");
|
||||
style.setProperty("--timings-scale", scale);
|
||||
style.setProperty("--timings-rev-scale", 1 / scale);
|
||||
}
|
||||
|
||||
isScrolledToBottom() {
|
||||
const { contentEl } = this.refs;
|
||||
const lastChildEl = contentEl.lastElementChild;
|
||||
@ -250,6 +223,7 @@ class RequestListContent extends Component {
|
||||
onSecurityIconMouseDown,
|
||||
onThumbnailMouseDown,
|
||||
onWaterfallMouseDown,
|
||||
scale,
|
||||
selectedRequestId,
|
||||
} = this.props;
|
||||
|
||||
@ -261,6 +235,7 @@ class RequestListContent extends Component {
|
||||
className: "requests-list-contents",
|
||||
tabIndex: 0,
|
||||
onKeyDown: this.onKeyDown,
|
||||
style: {"--timings-scale": scale, "--timings-rev-scale": 1 / scale}
|
||||
},
|
||||
RequestListHeader(),
|
||||
displayedRequests.map((item, index) => RequestListItem({
|
||||
|
@ -1601,12 +1601,23 @@ HTMLMediaElement::MozRequestDebugInfo(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::MozDumpDebugInfo()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->DumpDebugInfo();
|
||||
ErrorResult rv;
|
||||
RefPtr<Promise> promise = CreateDOMPromise(rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->DumpDebugInfo()->Then(mAbstractMainThread,
|
||||
__func__,
|
||||
promise.get(),
|
||||
&Promise::MaybeResolveWithUndefined);
|
||||
} else {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
}
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@ -6288,7 +6299,8 @@ nsresult HTMLMediaElement::DispatchEvent(const nsAString& aName)
|
||||
false);
|
||||
}
|
||||
|
||||
nsresult HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
||||
void
|
||||
HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
||||
{
|
||||
LOG_EVENT(LogLevel::Debug, ("%p Queuing event %s", this,
|
||||
NS_ConvertUTF16toUTF8(aName).get()));
|
||||
@ -6297,7 +6309,7 @@ nsresult HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
||||
// if the page comes out of the bfcache.
|
||||
if (mEventDeliveryPaused) {
|
||||
mPendingEvents.AppendElement(aName);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
@ -6322,8 +6334,6 @@ nsresult HTMLMediaElement::DispatchAsyncEvent(const nsAString& aName)
|
||||
mPlayTime.Pause();
|
||||
HiddenVideoStop();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HTMLMediaElement::DispatchPendingMediaEvents()
|
||||
|
@ -220,9 +220,9 @@ public:
|
||||
// suspended the channel.
|
||||
virtual void NotifySuspendedByCache(bool aSuspendedByCache) final override;
|
||||
|
||||
virtual bool IsActive() const final override;
|
||||
bool IsActive() const;
|
||||
|
||||
virtual bool IsHidden() const final override;
|
||||
bool IsHidden() const;
|
||||
|
||||
// Called by the media decoder and the video frame to get the
|
||||
// ImageContainer containing the video data.
|
||||
@ -246,7 +246,7 @@ public:
|
||||
const PrincipalHandle& aNewPrincipalHandle);
|
||||
|
||||
// Dispatch events
|
||||
virtual nsresult DispatchAsyncEvent(const nsAString& aName) final override;
|
||||
virtual void DispatchAsyncEvent(const nsAString& aName) final override;
|
||||
|
||||
// Triggers a recomputation of readyState.
|
||||
void UpdateReadyState() override { UpdateReadyStateInternal(); }
|
||||
@ -624,7 +624,7 @@ public:
|
||||
// data from decoder/reader/MDSM. Used for debugging purposes.
|
||||
already_AddRefed<Promise> MozRequestDebugInfo(ErrorResult& aRv);
|
||||
|
||||
void MozDumpDebugInfo();
|
||||
already_AddRefed<Promise> MozDumpDebugInfo();
|
||||
|
||||
// For use by mochitests. Enabling pref "media.test.video-suspend"
|
||||
void SetVisible(bool aVisible);
|
||||
|
@ -1255,6 +1255,23 @@ MediaCache::Update()
|
||||
break;
|
||||
}
|
||||
|
||||
// Don't evict |destinationBlockIndex| if it is within [cur, end) otherwise
|
||||
// a new channel will be opened to download this block again which is bad.
|
||||
bool inCurrentCachedRange = false;
|
||||
for (BlockOwner& owner : mIndex[destinationBlockIndex].mOwners) {
|
||||
MediaCacheStream* stream = owner.mStream;
|
||||
int64_t end = OffsetToBlockIndexUnchecked(
|
||||
stream->GetCachedDataEndInternal(stream->mStreamOffset));
|
||||
int64_t cur = OffsetToBlockIndexUnchecked(stream->mStreamOffset);
|
||||
if (cur <= owner.mStreamBlock && owner.mStreamBlock < end) {
|
||||
inCurrentCachedRange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (inCurrentCachedRange) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsBlockFree(destinationBlockIndex) ||
|
||||
PredictNextUse(now, destinationBlockIndex) > latestPredictedUseForOverflow) {
|
||||
// Reuse blocks in the main part of the cache that are less useful than
|
||||
|
@ -1553,7 +1553,7 @@ MediaDecoder::GetDebugInfo()
|
||||
PlayStateStr());
|
||||
}
|
||||
|
||||
void
|
||||
RefPtr<GenericPromise>
|
||||
MediaDecoder::DumpDebugInfo()
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
|
||||
@ -1568,17 +1568,20 @@ MediaDecoder::DumpDebugInfo()
|
||||
|
||||
if (!GetStateMachine()) {
|
||||
DUMP("%s", str.get());
|
||||
return;
|
||||
return GenericPromise::CreateAndResolve(true, __func__);
|
||||
}
|
||||
|
||||
GetStateMachine()->RequestDebugInfo()->Then(
|
||||
SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
|
||||
[str] (const nsACString& aString) {
|
||||
return GetStateMachine()->RequestDebugInfo()->Then(
|
||||
SystemGroup::AbstractMainThreadFor(TaskCategory::Other),
|
||||
__func__,
|
||||
[str](const nsACString& aString) {
|
||||
DUMP("%s", str.get());
|
||||
DUMP("%s", aString.Data());
|
||||
return GenericPromise::CreateAndResolve(true, __func__);
|
||||
},
|
||||
[str] () {
|
||||
[str]() {
|
||||
DUMP("%s", str.get());
|
||||
return GenericPromise::CreateAndResolve(true, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -389,7 +389,7 @@ private:
|
||||
// data. Used for debugging purposes.
|
||||
virtual void GetMozDebugReaderData(nsACString& aString);
|
||||
|
||||
virtual void DumpDebugInfo();
|
||||
RefPtr<GenericPromise> DumpDebugInfo();
|
||||
|
||||
using DebugInfoPromise = MozPromise<nsCString, bool, true>;
|
||||
RefPtr<DebugInfoPromise> RequestDebugInfo();
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
virtual void DownloadProgressed() = 0;
|
||||
|
||||
// Dispatch an asynchronous event to the decoder owner
|
||||
virtual nsresult DispatchAsyncEvent(const nsAString& aName) = 0;
|
||||
virtual void DispatchAsyncEvent(const nsAString& aName) = 0;
|
||||
|
||||
// Triggers a recomputation of readyState.
|
||||
virtual void UpdateReadyState() = 0;
|
||||
@ -118,12 +118,6 @@ public:
|
||||
NEXT_FRAME_UNINITIALIZED
|
||||
};
|
||||
|
||||
// Check if the decoder owner is active.
|
||||
virtual bool IsActive() const = 0;
|
||||
|
||||
// Check if the decoder owner is hidden.
|
||||
virtual bool IsHidden() const = 0;
|
||||
|
||||
// Called by media decoder when the audible state changed
|
||||
virtual void SetAudibleState(bool aAudible) = 0;
|
||||
|
||||
|
@ -14,10 +14,7 @@ namespace mozilla
|
||||
class MockMediaDecoderOwner : public MediaDecoderOwner
|
||||
{
|
||||
public:
|
||||
nsresult DispatchAsyncEvent(const nsAString& aName) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
void DispatchAsyncEvent(const nsAString& aName) override {}
|
||||
void FireTimeUpdate(bool aPeriodic) override {}
|
||||
bool GetPaused() override { return false; }
|
||||
void MetadataLoaded(const MediaInfo* aInfo,
|
||||
@ -36,8 +33,6 @@ public:
|
||||
void FirstFrameLoaded() override {}
|
||||
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) override {}
|
||||
bool IsActive() const override { return true; }
|
||||
bool IsHidden() const override { return false; }
|
||||
void DownloadSuspended() override {}
|
||||
void DownloadResumed(bool aForceNetworkLoading) override {}
|
||||
void NotifySuspendedByCache(bool aIsSuspended) override {}
|
||||
|
@ -1630,8 +1630,6 @@ function MediaTestManager() {
|
||||
// Instead MediaTestManager will manage timeout of each test.
|
||||
SimpleTest.requestLongerTimeout(1000);
|
||||
|
||||
this.hasTimeout = false;
|
||||
|
||||
// Return how many seconds elapsed since |begin|.
|
||||
function elapsedTime(begin) {
|
||||
var end = new Date();
|
||||
@ -1683,10 +1681,10 @@ function MediaTestManager() {
|
||||
this.numTestsRunning++;
|
||||
this.handlers[token] = handler;
|
||||
|
||||
var onTimeout = () => {
|
||||
this.hasTimeout = true;
|
||||
var onTimeout = async () => {
|
||||
ok(false, "Test timed out!");
|
||||
info(`${token} timed out!`);
|
||||
await dumpDebugInfoForToken(token);
|
||||
this.finished(token);
|
||||
};
|
||||
// Default timeout to 180s for each test.
|
||||
@ -1752,9 +1750,6 @@ function MediaTestManager() {
|
||||
if (this.onFinished) {
|
||||
this.onFinished();
|
||||
}
|
||||
if (this.hasTimeout) {
|
||||
dumpDebugInfo();
|
||||
}
|
||||
var onCleanup = () => {
|
||||
var end = new Date();
|
||||
SimpleTest.info("Finished at " + end + " (" + (end.getTime() / 1000) + "s)");
|
||||
@ -1789,6 +1784,20 @@ function isSlowPlatform() {
|
||||
return SpecialPowers.Services.appinfo.name == "B2G" || getAndroidVersion() == 10;
|
||||
}
|
||||
|
||||
async function dumpDebugInfoForToken(token) {
|
||||
for (let v of document.getElementsByTagName("video")) {
|
||||
if (token === v.token) {
|
||||
return v.mozDumpDebugInfo();
|
||||
}
|
||||
}
|
||||
for (let a of document.getElementsByTagName("audio")) {
|
||||
if (token === a.token) {
|
||||
return a.mozDumpDebugInfo();
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function dumpDebugInfo() {
|
||||
for (var v of document.getElementsByTagName("video")) {
|
||||
v.mozDumpDebugInfo();
|
||||
|
@ -108,7 +108,7 @@ partial interface HTMLMediaElement {
|
||||
Promise<DOMString> mozRequestDebugInfo();
|
||||
|
||||
[Pref="media.test.dumpDebugInfo"]
|
||||
void mozDumpDebugInfo();
|
||||
Promise<void> mozDumpDebugInfo();
|
||||
|
||||
attribute MediaStream? srcObject;
|
||||
|
||||
|
@ -7270,6 +7270,38 @@ nsTextFrame::DrawTextRunAndDecorations(Range aRange,
|
||||
PaintDecorationLine(params);
|
||||
};
|
||||
|
||||
// We create a clip region in order to draw the decoration lines only in the
|
||||
// range of the text. Restricting the draw area prevents the decoration lines
|
||||
// to be drawn multiple times when a part of the text is selected.
|
||||
|
||||
// We skip clipping for the following cases:
|
||||
// - drawing the whole text
|
||||
// - having different orientation of the text and the writing-mode, such as
|
||||
// "text-combine-upright" (Bug 1408825)
|
||||
bool skipClipping = aRange.Length() == mTextRun->GetLength() ||
|
||||
verticalDec != verticalRun;
|
||||
|
||||
gfxRect clipRect;
|
||||
if (!skipClipping) {
|
||||
// Get the inline-size according to the specified range.
|
||||
gfxFloat clipLength = mTextRun->GetAdvanceWidth(aRange, aParams.provider);
|
||||
|
||||
clipRect.width = verticalDec ? frameSize.width : clipLength / app;
|
||||
clipRect.height = verticalDec ? clipLength / app : frameSize.height;
|
||||
|
||||
const bool isInlineReversed = mTextRun->IsInlineReversed();
|
||||
if (verticalDec) {
|
||||
clipRect.y = (isInlineReversed ? aTextBaselinePt.y - clipLength
|
||||
: aTextBaselinePt.y) / app;
|
||||
} else {
|
||||
clipRect.x = (isInlineReversed ? aTextBaselinePt.x - clipLength
|
||||
: aTextBaselinePt.x) / app;
|
||||
}
|
||||
|
||||
clipRect.Round();
|
||||
params.context->Clip(clipRect);
|
||||
}
|
||||
|
||||
// Underlines
|
||||
params.decoration = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
|
||||
for (const LineDecoration& dec : Reversed(aDecorations.mUnderlines)) {
|
||||
@ -7283,6 +7315,12 @@ nsTextFrame::DrawTextRunAndDecorations(Range aRange,
|
||||
paintDecorationLine(dec, &Metrics::underlineSize, &Metrics::maxAscent);
|
||||
}
|
||||
|
||||
// Some glyphs and emphasis marks may extend outside the region, so we reset
|
||||
// the clip region here. For an example, italic glyphs.
|
||||
if (!skipClipping) {
|
||||
params.context->PopClip();
|
||||
}
|
||||
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore unscaledRestorer;
|
||||
if (scaledRestorer.HasMatrix()) {
|
||||
@ -7300,12 +7338,21 @@ nsTextFrame::DrawTextRunAndDecorations(Range aRange,
|
||||
aTextBaselinePt, aParams.framePt, aRange,
|
||||
aParams.decorationOverrideColor, aParams.provider);
|
||||
|
||||
// Re-apply the clip region when the line-through is being drawn.
|
||||
if (!skipClipping) {
|
||||
params.context->Clip(clipRect);
|
||||
}
|
||||
|
||||
// Line-throughs
|
||||
params.decoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
|
||||
for (const LineDecoration& dec : Reversed(aDecorations.mStrikes)) {
|
||||
paintDecorationLine(dec, &Metrics::strikeoutSize,
|
||||
&Metrics::strikeoutOffset);
|
||||
}
|
||||
|
||||
if (!skipClipping) {
|
||||
params.context->PopClip();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -34,7 +34,7 @@ fuzzy-if(skiaContent,1,1200) == addrange-2.html addrange-ref.html
|
||||
== splitText-normalize.html splitText-normalize-ref.html
|
||||
== modify-range.html modify-range-ref.html
|
||||
== dom-mutations.html dom-mutations-ref.html
|
||||
fuzzy-if(OSX==1010,9,1) fuzzy-if(OSX&&skiaContent,6,1) fuzzy-if(skiaContent&&!OSX,1,2138) == trailing-space-1.html trailing-space-1-ref.html
|
||||
fuzzy-if(OSX==1010,9,1) fuzzy-if(OSX&&skiaContent,6,1) fuzzy-if(skiaContent&&!OSX,1,2138) fails-if(webrender) == trailing-space-1.html trailing-space-1-ref.html # Bug 1414125
|
||||
!= invalidation-1-ref.html invalidation-2-ref.html
|
||||
== invalidation-1a.html invalidation-1-ref.html
|
||||
== invalidation-1b.html invalidation-1-ref.html
|
||||
@ -48,3 +48,6 @@ fuzzy-if(OSX==1010,9,1) fuzzy-if(OSX&&skiaContent,6,1) fuzzy-if(skiaContent&&!OS
|
||||
== invalidation-2d.html invalidation-2-ref.html
|
||||
== invalidation-2e.html invalidation-2-ref.html
|
||||
== invalidation-2f.html invalidation-2-ref.html
|
||||
fuzzy(7,2) fuzzy-if(OSX,1,1) fails-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == rtl-selection-with-decoration.html rtl-selection-with-decoration-ref.html
|
||||
fails-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == semitransparent-decoration-line.html semitransparent-decoration-line-ref.html
|
||||
fuzzy-if(OSX,1,6) fails-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)&&isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == writing-mode.html writing-mode-ref.html
|
||||
|
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>rtl-selection-with-decoration-ref</title>
|
||||
<style>
|
||||
p {
|
||||
font-size: 2em;
|
||||
text-decoration-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
#text1 {
|
||||
text-decoration-line: line-through underline;
|
||||
}
|
||||
#text2 {
|
||||
text-decoration-line: line-through overline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="text1" lang="he">זוהי עובדה הקורא שדעתו מבוססת של תהיה</p>
|
||||
<p id="text2" lang="he" dir="rtl">זוהי עובדה הקורא שדעתו מבוססת של תהיה</p>
|
||||
</body>
|
||||
</html>
|
39
layout/reftests/selection/rtl-selection-with-decoration.html
Normal file
39
layout/reftests/selection/rtl-selection-with-decoration.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>rtl-selection-with-decoration</title>
|
||||
<style>
|
||||
p {
|
||||
font-size: 2em;
|
||||
text-decoration-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
#text1 {
|
||||
text-decoration-line: line-through underline;
|
||||
}
|
||||
#text2 {
|
||||
text-decoration-line: line-through overline;
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
function select() {
|
||||
window.getSelection().removeAllRanges();
|
||||
var elems = document.getElementsByTagName('p');
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
var range = document.createRange();
|
||||
range.setStart(elems[i].firstChild, 2);
|
||||
range.setEnd(elems[i].firstChild, 9);
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="select()">
|
||||
<p id="text1" lang="he">זוהי עובדה הקורא שדעתו מבוססת של תהיה</p>
|
||||
<p id="text2" lang="he" dir="rtl">זוהי עובדה הקורא שדעתו מבוססת של תהיה</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>semitransparent-decoration-line-ref</title>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
.overline {
|
||||
text-decoration: overline rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
.line-through {
|
||||
text-decoration: line-through rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="underline">Lorem ipsum dolor sit amet</p>
|
||||
<p class="overline">Lorem ipsum dolor sit amet</p>
|
||||
<p class="line-through">Lorem ipsum dolor sit amet</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>semitransparent-decoration-line</title>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
.overline {
|
||||
text-decoration: overline rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
.line-through {
|
||||
text-decoration: line-through rgba(0,0,0,0.3);
|
||||
font-size: 2em;
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
function select() {
|
||||
window.getSelection().removeAllRanges();
|
||||
var elems = document.getElementsByTagName('p');
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
var range = document.createRange();
|
||||
range.setStart(elems[i].firstChild, 2);
|
||||
range.setEnd(elems[i].firstChild, 9);
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="select()">
|
||||
<p class="underline">Lorem ipsum dolor sit amet</p>
|
||||
<p class="overline">Lorem ipsum dolor sit amet</p>
|
||||
<p class="line-through">Lorem ipsum dolor sit amet</p>
|
||||
</body>
|
||||
</html>
|
39
layout/reftests/selection/writing-mode-ref.html
Normal file
39
layout/reftests/selection/writing-mode-ref.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>writing-mode-ref</title>
|
||||
<style>
|
||||
p {
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
}
|
||||
.line-through {
|
||||
text-decoration: line-through wavy rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.wm-vertical-lr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.wm-vertical-rl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.wm-sideways-lr {
|
||||
writing-mode: sideways-lr;
|
||||
}
|
||||
.wm-sideways-rl {
|
||||
writing-mode: sideways-rl;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p lang="zh" dir="ltr" class="wm-vertical-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-vertical-rl line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-sideways-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-sideways-rl line-through">你好世界!Hello World!</p>
|
||||
<br/>
|
||||
<p lang="zh" dir="rtl" class="wm-vertical-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-vertical-rl line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-sideways-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-sideways-rl line-through">你好世界!Hello World!</p>
|
||||
</body>
|
||||
</html>
|
56
layout/reftests/selection/writing-mode.html
Normal file
56
layout/reftests/selection/writing-mode.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>writing-mode</title>
|
||||
<style>
|
||||
p {
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
}
|
||||
.line-through {
|
||||
text-decoration: line-through wavy rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
.wm-vertical-lr {
|
||||
writing-mode: vertical-lr;
|
||||
display: inline-block;
|
||||
}
|
||||
.wm-vertical-rl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.wm-sideways-lr {
|
||||
writing-mode: sideways-lr;
|
||||
}
|
||||
.wm-sideways-rl {
|
||||
writing-mode: sideways-rl;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
function select() {
|
||||
window.getSelection().removeAllRanges();
|
||||
var elems = document.getElementsByTagName('p');
|
||||
for (var i = 0; i < elems.length; ++i) {
|
||||
var range = document.createRange();
|
||||
range.setStart(elems[i].firstChild, 2);
|
||||
range.setEnd(elems[i].firstChild, 9);
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="select()">
|
||||
<p lang="zh" dir="ltr" class="wm-vertical-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-vertical-rl line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-sideways-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="ltr" class="wm-sideways-rl line-through">你好世界!Hello World!</p>
|
||||
<br/>
|
||||
<p lang="zh" dir="rtl" class="wm-vertical-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-vertical-rl line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-sideways-lr line-through">你好世界!Hello World!</p>
|
||||
<p lang="zh" dir="rtl" class="wm-sideways-rl line-through">你好世界!Hello World!</p>
|
||||
</body>
|
||||
</html>
|
@ -13,7 +13,7 @@ random-if(Android) == basic-negcoord.xul basic-negcoord-ref.xul
|
||||
!= blur.html blur-notref.html
|
||||
== color-inherit.html color-inherit-ref.html
|
||||
== color-parserorder.html color-parserorder-ref.html
|
||||
== decorations-multiple-zorder.html decorations-multiple-zorder-ref.html
|
||||
fails-if(webrender) == decorations-multiple-zorder.html decorations-multiple-zorder-ref.html # Bug 1414125
|
||||
== multiple-noblur.html multiple-noblur-ref.html
|
||||
== quirks-decor-noblur.html quirks-decor-noblur-ref.html
|
||||
== standards-decor-noblur.html standards-decor-noblur-ref.html
|
||||
|
@ -962,14 +962,16 @@ H264::HasSPS(const mozilla::MediaByteBuffer* aExtraData)
|
||||
/* static */ uint8_t
|
||||
H264::NumSPS(const mozilla::MediaByteBuffer* aExtraData)
|
||||
{
|
||||
if (!aExtraData) {
|
||||
if (!aExtraData || aExtraData->IsEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BufferReader reader(aExtraData);
|
||||
const uint8_t* ptr = reader.Read(5);
|
||||
if (!reader.Read(5)) {
|
||||
return 0;
|
||||
}
|
||||
auto res = reader.ReadU8();
|
||||
if (!ptr || res.isErr()) {
|
||||
if (res.isErr()) {
|
||||
return 0;
|
||||
}
|
||||
return res.unwrap() & 0x1f;
|
||||
|
4
servo/Cargo.lock
generated
4
servo/Cargo.lock
generated
@ -3476,7 +3476,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "webrender"
|
||||
version = "0.53.1"
|
||||
source = "git+https://github.com/servo/webrender#82e85d7f407ff38f08fb0901724918704d6d2e4a"
|
||||
source = "git+https://github.com/servo/webrender#058dd77d35d938974d16dcf12e2f75a0a6e4cdef"
|
||||
dependencies = [
|
||||
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3503,7 +3503,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "webrender_api"
|
||||
version = "0.53.1"
|
||||
source = "git+https://github.com/servo/webrender#82e85d7f407ff38f08fb0901724918704d6d2e4a"
|
||||
source = "git+https://github.com/servo/webrender#058dd77d35d938974d16dcf12e2f75a0a6e4cdef"
|
||||
dependencies = [
|
||||
"app_units 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bincode 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(328daa3e-09e4-455f-bb6f-0a921766042f)]
|
||||
[scriptable, uuid(72006d06-a2a5-4250-ae92-04b2f0e2ab8d)]
|
||||
interface nsIPrintingPromptService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -38,7 +38,6 @@ interface nsIPrintingPromptService : nsISupports
|
||||
* showPrintDialog - displays a native dialog
|
||||
* showPageSetup - displays a XUL dialog
|
||||
* showProgress - displays a XUL dialog
|
||||
* showPrinterProperties - n/a
|
||||
*
|
||||
* Summary for Windows Embedders:
|
||||
* Stated once again: There is no "fallback" native platform support in GFX for the
|
||||
@ -49,7 +48,7 @@ interface nsIPrintingPromptService : nsISupports
|
||||
*
|
||||
* Note: The Windows version Mozilla implements this service which is
|
||||
* automatically built and registered for you. You can use it as an example.
|
||||
* It is located at "mozilla/toolkit/components/printingui/win". That service
|
||||
* It is located at "widget/windows/nsPrintDialogService.cpp". That service
|
||||
* is capable of displaying a native print dialog and a XUL progress dialog.
|
||||
*
|
||||
* To fly your own dialog you may:
|
||||
@ -73,20 +72,17 @@ interface nsIPrintingPromptService : nsISupports
|
||||
* Mac OS9: showPrintDialog - displays a native dialog
|
||||
* showPageSetup - displays a native dialog
|
||||
* showProgress - displays a XUL dialog
|
||||
* showPrinterProperties - n/a
|
||||
*
|
||||
*
|
||||
* Mac OSX: showPrintDialog - displays a native dialog
|
||||
* showPageSetup - displays a native dialog
|
||||
* showProgress - not implemented (provided by OS)
|
||||
* showPrinterProperties - n/a
|
||||
*
|
||||
*
|
||||
* GTK: There are no native dialog for GTK.
|
||||
*
|
||||
* Defaults for platform service:
|
||||
* showPrintDialog - displays a XUL dialog
|
||||
* showPageSetup - displays a XUL dialog
|
||||
* Defaults for platform service:
|
||||
* showPrintDialog - displays a native dialog
|
||||
* showPageSetup - displays a native dialog
|
||||
* showProgress - displays a XUL dialog
|
||||
* showPrinterProperties - displays a XUL dialog
|
||||
*
|
||||
*/
|
||||
|
||||
@ -141,20 +137,6 @@ interface nsIPrintingPromptService : nsISupports
|
||||
in nsIPrintSettings printSettings,
|
||||
in nsIObserver aObs);
|
||||
|
||||
/**
|
||||
* Sometimes platforms need to bring up a special properties dialog for showing
|
||||
* print specific properties. Although the PrintSettings has a place to set the
|
||||
* printer name, here is is an argument to be clear as to what printer is being
|
||||
* asked to have the properties set for it. The Printer name in the PS is ignored.
|
||||
*
|
||||
* @param parent - a DOM windows the dialog will be parented to (required)
|
||||
* @param printerName - name of printer (required)
|
||||
* @param printSettings - PrintSettings for page setup (required)
|
||||
*/
|
||||
void showPrinterProperties(in mozIDOMWindowProxy parent,
|
||||
in wstring printerName,
|
||||
in nsIPrintSettings printSettings);
|
||||
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -1,408 +0,0 @@
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var dialog;
|
||||
var printService = null;
|
||||
var gOriginalNumCopies = 1;
|
||||
|
||||
var paramBlock;
|
||||
var gPrefs = null;
|
||||
var gPrintSettings = null;
|
||||
var gWebBrowserPrint = null;
|
||||
var gPrintSetInterface = Components.interfaces.nsIPrintSettings;
|
||||
var doDebug = false;
|
||||
|
||||
// ---------------------------------------------------
|
||||
function initDialog() {
|
||||
dialog = {};
|
||||
|
||||
dialog.propertiesButton = document.getElementById("properties");
|
||||
dialog.descText = document.getElementById("descText");
|
||||
|
||||
dialog.printrangeGroup = document.getElementById("printrangeGroup");
|
||||
dialog.allpagesRadio = document.getElementById("allpagesRadio");
|
||||
dialog.rangeRadio = document.getElementById("rangeRadio");
|
||||
dialog.selectionRadio = document.getElementById("selectionRadio");
|
||||
dialog.frompageInput = document.getElementById("frompageInput");
|
||||
dialog.frompageLabel = document.getElementById("frompageLabel");
|
||||
dialog.topageInput = document.getElementById("topageInput");
|
||||
dialog.topageLabel = document.getElementById("topageLabel");
|
||||
|
||||
dialog.numCopiesInput = document.getElementById("numCopiesInput");
|
||||
|
||||
dialog.printframeGroup = document.getElementById("printframeGroup");
|
||||
dialog.aslaidoutRadio = document.getElementById("aslaidoutRadio");
|
||||
dialog.selectedframeRadio = document.getElementById("selectedframeRadio");
|
||||
dialog.eachframesepRadio = document.getElementById("eachframesepRadio");
|
||||
dialog.printframeGroupLabel = document.getElementById("printframeGroupLabel");
|
||||
|
||||
dialog.fileCheck = document.getElementById("fileCheck");
|
||||
dialog.printerLabel = document.getElementById("printerLabel");
|
||||
dialog.printerList = document.getElementById("printerList");
|
||||
|
||||
dialog.printButton = document.documentElement.getButton("accept");
|
||||
|
||||
// <data> elements
|
||||
dialog.printName = document.getElementById("printButton");
|
||||
dialog.fpDialog = document.getElementById("fpDialog");
|
||||
|
||||
dialog.enabled = false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function checkInteger(element) {
|
||||
var value = element.value;
|
||||
if (value && value.length > 0) {
|
||||
value = value.replace(/[^0-9]/g, "");
|
||||
if (!value) value = "";
|
||||
element.value = value;
|
||||
}
|
||||
if (!value || value < 1 || value > 999)
|
||||
dialog.printButton.setAttribute("disabled", "true");
|
||||
else
|
||||
dialog.printButton.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function stripTrailingWhitespace(element) {
|
||||
var value = element.value;
|
||||
value = value.replace(/\s+$/, "");
|
||||
element.value = value;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function getPrinterDescription(printerName) {
|
||||
return gPrefs.getCharPref("print.printer_" + printerName + ".printer_description", "");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function listElement(aListElement) {
|
||||
this.listElement = aListElement;
|
||||
}
|
||||
|
||||
listElement.prototype =
|
||||
{
|
||||
clearList() {
|
||||
// remove the menupopup node child of the menulist.
|
||||
var popup = this.listElement.firstChild;
|
||||
if (popup) {
|
||||
this.listElement.removeChild(popup);
|
||||
}
|
||||
},
|
||||
|
||||
appendPrinterNames(aDataObject) {
|
||||
if ((null == aDataObject) || !aDataObject.hasMore()) {
|
||||
// disable dialog
|
||||
this.listElement.setAttribute("value", "");
|
||||
this.listElement.setAttribute("label",
|
||||
document.getElementById("printingBundle")
|
||||
.getString("noprinter"));
|
||||
|
||||
this.listElement.setAttribute("disabled", "true");
|
||||
dialog.printerLabel.setAttribute("disabled", "true");
|
||||
dialog.propertiesButton.setAttribute("disabled", "true");
|
||||
dialog.fileCheck.setAttribute("disabled", "true");
|
||||
dialog.printButton.setAttribute("disabled", "true");
|
||||
} else {
|
||||
// build popup menu from printer names
|
||||
var list = document.getElementById("printerList");
|
||||
do {
|
||||
let printerNameStr = aDataObject.getNext();
|
||||
list.appendItem(printerNameStr, printerNameStr, getPrinterDescription(printerNameStr));
|
||||
} while (aDataObject.hasMore());
|
||||
this.listElement.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------
|
||||
function getPrinters() {
|
||||
var selectElement = new listElement(dialog.printerList);
|
||||
selectElement.clearList();
|
||||
|
||||
var printerEnumerator;
|
||||
try {
|
||||
printerEnumerator =
|
||||
Components.classes["@mozilla.org/gfx/printerenumerator;1"]
|
||||
.getService(Components.interfaces.nsIPrinterEnumerator)
|
||||
.printerNameList;
|
||||
} catch (e) { printerEnumerator = null; }
|
||||
|
||||
selectElement.appendPrinterNames(printerEnumerator);
|
||||
selectElement.listElement.value = printService.defaultPrinterName;
|
||||
|
||||
// make sure we load the prefs for the initially selected printer
|
||||
setPrinterDefaultsForSelectedPrinter();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------
|
||||
// update gPrintSettings with the defaults for the selected printer
|
||||
function setPrinterDefaultsForSelectedPrinter() {
|
||||
gPrintSettings.printerName = dialog.printerList.value;
|
||||
|
||||
dialog.descText.value = getPrinterDescription(gPrintSettings.printerName);
|
||||
|
||||
// First get any defaults from the printer
|
||||
printService.initPrintSettingsFromPrinter(gPrintSettings.printerName, gPrintSettings);
|
||||
|
||||
// now augment them with any values from last time
|
||||
printService.initPrintSettingsFromPrefs(gPrintSettings, true, gPrintSetInterface.kInitSaveAll);
|
||||
|
||||
if (doDebug) {
|
||||
dump("setPrinterDefaultsForSelectedPrinter: printerName='" + gPrintSettings.printerName + "', paperName='" + gPrintSettings.paperName + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function displayPropertiesDialog() {
|
||||
gPrintSettings.numCopies = dialog.numCopiesInput.value;
|
||||
try {
|
||||
var printingPromptService = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
|
||||
.getService(Components.interfaces.nsIPrintingPromptService);
|
||||
if (printingPromptService) {
|
||||
printingPromptService.showPrinterProperties(null, dialog.printerList.value, gPrintSettings);
|
||||
dialog.numCopiesInput.value = gPrintSettings.numCopies;
|
||||
}
|
||||
} catch (e) {
|
||||
dump("problems getting printingPromptService\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function doPrintRange(inx) {
|
||||
if (inx == 1) {
|
||||
dialog.frompageInput.removeAttribute("disabled");
|
||||
dialog.frompageLabel.removeAttribute("disabled");
|
||||
dialog.topageInput.removeAttribute("disabled");
|
||||
dialog.topageLabel.removeAttribute("disabled");
|
||||
} else {
|
||||
dialog.frompageInput.setAttribute("disabled", "true");
|
||||
dialog.frompageLabel.setAttribute("disabled", "true");
|
||||
dialog.topageInput.setAttribute("disabled", "true");
|
||||
dialog.topageLabel.setAttribute("disabled", "true");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function loadDialog() {
|
||||
var print_copies = 1;
|
||||
var print_selection_radio_enabled = false;
|
||||
var print_frametype = gPrintSetInterface.kSelectedFrame;
|
||||
var print_howToEnableUI = gPrintSetInterface.kFrameEnableNone;
|
||||
var print_tofile = "";
|
||||
|
||||
try {
|
||||
gPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
printService = Components.classes["@mozilla.org/gfx/printsettings-service;1"];
|
||||
if (printService) {
|
||||
printService = printService.getService();
|
||||
if (printService) {
|
||||
printService = printService.QueryInterface(Components.interfaces.nsIPrintSettingsService);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// Note: getPrinters sets up the PrintToFile control
|
||||
getPrinters();
|
||||
|
||||
if (gPrintSettings) {
|
||||
print_tofile = gPrintSettings.printToFile;
|
||||
gOriginalNumCopies = gPrintSettings.numCopies;
|
||||
|
||||
print_copies = gPrintSettings.numCopies;
|
||||
print_frametype = gPrintSettings.printFrameType;
|
||||
print_howToEnableUI = gPrintSettings.howToEnableFrameUI;
|
||||
print_selection_radio_enabled = gPrintSettings.GetPrintOptions(gPrintSetInterface.kEnableSelectionRB);
|
||||
}
|
||||
|
||||
if (doDebug) {
|
||||
dump("loadDialog*********************************************\n");
|
||||
dump("print_tofile " + print_tofile + "\n");
|
||||
dump("print_frame " + print_frametype + "\n");
|
||||
dump("print_howToEnableUI " + print_howToEnableUI + "\n");
|
||||
dump("selection_radio_enabled " + print_selection_radio_enabled + "\n");
|
||||
}
|
||||
|
||||
dialog.printrangeGroup.selectedItem = dialog.allpagesRadio;
|
||||
if (print_selection_radio_enabled) {
|
||||
dialog.selectionRadio.removeAttribute("disabled");
|
||||
} else {
|
||||
dialog.selectionRadio.setAttribute("disabled", "true");
|
||||
}
|
||||
doPrintRange(dialog.rangeRadio.selected);
|
||||
dialog.frompageInput.value = 1;
|
||||
dialog.topageInput.value = 1;
|
||||
dialog.numCopiesInput.value = print_copies;
|
||||
|
||||
if (doDebug) {
|
||||
dump("print_howToEnableUI: " + print_howToEnableUI + "\n");
|
||||
}
|
||||
|
||||
// print frame
|
||||
if (print_howToEnableUI == gPrintSetInterface.kFrameEnableAll) {
|
||||
dialog.aslaidoutRadio.removeAttribute("disabled");
|
||||
|
||||
dialog.selectedframeRadio.removeAttribute("disabled");
|
||||
dialog.eachframesepRadio.removeAttribute("disabled");
|
||||
dialog.printframeGroupLabel.removeAttribute("disabled");
|
||||
|
||||
// initialize radio group
|
||||
dialog.printframeGroup.selectedItem = dialog.selectedframeRadio;
|
||||
|
||||
} else if (print_howToEnableUI == gPrintSetInterface.kFrameEnableAsIsAndEach) {
|
||||
dialog.aslaidoutRadio.removeAttribute("disabled"); // enable
|
||||
|
||||
dialog.selectedframeRadio.setAttribute("disabled", "true"); // disable
|
||||
dialog.eachframesepRadio.removeAttribute("disabled"); // enable
|
||||
dialog.printframeGroupLabel.removeAttribute("disabled"); // enable
|
||||
|
||||
// initialize
|
||||
dialog.printframeGroup.selectedItem = dialog.eachframesepRadio;
|
||||
|
||||
} else {
|
||||
dialog.aslaidoutRadio.setAttribute("disabled", "true");
|
||||
dialog.selectedframeRadio.setAttribute("disabled", "true");
|
||||
dialog.eachframesepRadio.setAttribute("disabled", "true");
|
||||
dialog.printframeGroupLabel.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
dialog.printButton.label = dialog.printName.getAttribute("label");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function onLoad() {
|
||||
// Init dialog.
|
||||
initDialog();
|
||||
|
||||
// param[0]: nsIPrintSettings object
|
||||
// param[1]: container for return value (1 = print, 0 = cancel)
|
||||
|
||||
gPrintSettings = window.arguments[0].QueryInterface(gPrintSetInterface);
|
||||
gWebBrowserPrint = window.arguments[1].QueryInterface(Components.interfaces.nsIWebBrowserPrint);
|
||||
paramBlock = window.arguments[2].QueryInterface(Components.interfaces.nsIDialogParamBlock);
|
||||
|
||||
// default return value is "cancel"
|
||||
paramBlock.SetInt(0, 0);
|
||||
|
||||
loadDialog();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function onAccept() {
|
||||
let promise;
|
||||
|
||||
if (gPrintSettings == null) {
|
||||
promise = Promise.resolve();
|
||||
} else {
|
||||
var print_howToEnableUI = gPrintSetInterface.kFrameEnableNone;
|
||||
|
||||
// save these out so they can be picked up by the device spec
|
||||
gPrintSettings.printerName = dialog.printerList.value;
|
||||
print_howToEnableUI = gPrintSettings.howToEnableFrameUI;
|
||||
gPrintSettings.printToFile = dialog.fileCheck.checked;
|
||||
|
||||
if (gPrintSettings.printToFile) {
|
||||
promise = chooseFile();
|
||||
} else {
|
||||
promise = Promise.resolve();
|
||||
}
|
||||
|
||||
promise = promise.then(() => {
|
||||
if (dialog.allpagesRadio.selected) {
|
||||
gPrintSettings.printRange = gPrintSetInterface.kRangeAllPages;
|
||||
} else if (dialog.rangeRadio.selected) {
|
||||
gPrintSettings.printRange = gPrintSetInterface.kRangeSpecifiedPageRange;
|
||||
} else if (dialog.selectionRadio.selected) {
|
||||
gPrintSettings.printRange = gPrintSetInterface.kRangeSelection;
|
||||
}
|
||||
gPrintSettings.startPageRange = dialog.frompageInput.value;
|
||||
gPrintSettings.endPageRange = dialog.topageInput.value;
|
||||
gPrintSettings.numCopies = dialog.numCopiesInput.value;
|
||||
|
||||
var frametype = gPrintSetInterface.kNoFrames;
|
||||
if (print_howToEnableUI != gPrintSetInterface.kFrameEnableNone) {
|
||||
if (dialog.aslaidoutRadio.selected) {
|
||||
frametype = gPrintSetInterface.kFramesAsIs;
|
||||
} else if (dialog.selectedframeRadio.selected) {
|
||||
frametype = gPrintSetInterface.kSelectedFrame;
|
||||
} else if (dialog.eachframesepRadio.selected) {
|
||||
frametype = gPrintSetInterface.kEachFrameSep;
|
||||
} else {
|
||||
frametype = gPrintSetInterface.kSelectedFrame;
|
||||
}
|
||||
}
|
||||
gPrintSettings.printFrameType = frametype;
|
||||
if (doDebug) {
|
||||
dump("onAccept*********************************************\n");
|
||||
dump("frametype " + frametype + "\n");
|
||||
dump("numCopies " + gPrintSettings.numCopies + "\n");
|
||||
dump("printRange " + gPrintSettings.printRange + "\n");
|
||||
dump("printerName " + gPrintSettings.printerName + "\n");
|
||||
dump("startPageRange " + gPrintSettings.startPageRange + "\n");
|
||||
dump("endPageRange " + gPrintSettings.endPageRange + "\n");
|
||||
dump("printToFile " + gPrintSettings.printToFile + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
promise.then(() => {
|
||||
var saveToPrefs = false;
|
||||
|
||||
saveToPrefs = gPrefs.getBoolPref("print.save_print_settings");
|
||||
|
||||
if (saveToPrefs && printService != null) {
|
||||
var flags = gPrintSetInterface.kInitSavePaperSize |
|
||||
gPrintSetInterface.kInitSaveEdges |
|
||||
gPrintSetInterface.kInitSaveInColor |
|
||||
gPrintSetInterface.kInitSaveShrinkToFit |
|
||||
gPrintSetInterface.kInitSaveScaling;
|
||||
printService.savePrintSettingsToPrefs(gPrintSettings, true, flags);
|
||||
}
|
||||
|
||||
// set return value to "print"
|
||||
if (paramBlock) {
|
||||
paramBlock.SetInt(0, 1);
|
||||
} else {
|
||||
dump("*** FATAL ERROR: No paramBlock\n");
|
||||
}
|
||||
|
||||
window.close();
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function onCancel() {
|
||||
// set return value to "cancel"
|
||||
if (paramBlock) {
|
||||
paramBlock.SetInt(0, 0);
|
||||
} else {
|
||||
dump("*** FATAL ERROR: No paramBlock\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
const nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
function chooseFile() {
|
||||
return new Promise(resolve => {
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
fp.init(window, dialog.fpDialog.getAttribute("label"), nsIFilePicker.modeSave);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
fp.open(rv => {
|
||||
if (rv != Components.interfaces.nsIFilePicker.returnCancel &&
|
||||
fp.file && fp.file.path) {
|
||||
gPrintSettings.toFileName = fp.file.path;
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<!DOCTYPE dialog SYSTEM "chrome://global/locale/printdialog.dtd">
|
||||
|
||||
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="onLoad();"
|
||||
ondialogaccept="return onAccept();"
|
||||
oncancel="return onCancel();"
|
||||
buttoniconaccept="print"
|
||||
title="&printDialog.title;"
|
||||
persist="screenX screenY"
|
||||
screenX="24" screenY="24">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/printdialog.js"/>
|
||||
|
||||
<stringbundle id="printingBundle" src="chrome://global/locale/printing.properties"/>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&printer.label;"/>
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
|
||||
<rows>
|
||||
<row align="center">
|
||||
<hbox align="center" pack="end">
|
||||
<label id="printerLabel"
|
||||
value="&printerInput.label;"
|
||||
accesskey="&printerInput.accesskey;"
|
||||
control="printerList"/>
|
||||
</hbox>
|
||||
<menulist id="printerList" flex="1" type="description" oncommand="setPrinterDefaultsForSelectedPrinter();"/>
|
||||
<button id="properties"
|
||||
label="&propertiesButton.label;"
|
||||
accesskey="&propertiesButton.accesskey;"
|
||||
icon="properties"
|
||||
oncommand="displayPropertiesDialog();"/>
|
||||
</row>
|
||||
<row align="center">
|
||||
<hbox align="center" pack="end">
|
||||
<label id="descTextLabel" control="descText" value="&descText.label;"/>
|
||||
</hbox>
|
||||
<label id="descText"/>
|
||||
<checkbox id="fileCheck"
|
||||
checked="false"
|
||||
label="&fileCheck.label;"
|
||||
accesskey="&fileCheck.accesskey;"
|
||||
pack="end"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
|
||||
<hbox>
|
||||
<groupbox flex="1">
|
||||
<caption label="&printrangeGroup.label;"/>
|
||||
|
||||
<radiogroup id="printrangeGroup">
|
||||
<radio id="allpagesRadio"
|
||||
label="&allpagesRadio.label;"
|
||||
accesskey="&allpagesRadio.accesskey;"
|
||||
oncommand="doPrintRange(0)"/>
|
||||
<hbox align="center">
|
||||
<radio id="rangeRadio"
|
||||
label="&rangeRadio.label;"
|
||||
accesskey="&rangeRadio.accesskey;"
|
||||
oncommand="doPrintRange(1)"/>
|
||||
<label id="frompageLabel"
|
||||
control="frompageInput"
|
||||
value="&frompageInput.label;"
|
||||
accesskey="&frompageInput.accesskey;"/>
|
||||
<textbox id="frompageInput" style="width:5em;" onkeyup="checkInteger(this)"/>
|
||||
<label id="topageLabel"
|
||||
control="topageInput"
|
||||
value="&topageInput.label;"
|
||||
accesskey="&topageInput.accesskey;"/>
|
||||
<textbox id="topageInput" style="width:5em;" onkeyup="checkInteger(this)"/>
|
||||
</hbox>
|
||||
<radio id="selectionRadio"
|
||||
label="&selectionRadio.label;"
|
||||
accesskey="&selectionRadio.accesskey;"
|
||||
oncommand="doPrintRange(2)"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
|
||||
<groupbox flex="1">
|
||||
<caption label="&copies.label;"/>
|
||||
<hbox align="center">
|
||||
<label control="numCopiesInput"
|
||||
value="&numCopies.label;"
|
||||
accesskey="&numCopies.accesskey;"/>
|
||||
<textbox id="numCopiesInput" style="width:5em;" onkeyup="checkInteger(this)"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</hbox>
|
||||
|
||||
<groupbox flex="1">
|
||||
<caption label="&printframeGroup.label;" id="printframeGroupLabel"/>
|
||||
<radiogroup id="printframeGroup">
|
||||
<radio id="aslaidoutRadio"
|
||||
label="&aslaidoutRadio.label;"
|
||||
accesskey="&aslaidoutRadio.accesskey;"/>
|
||||
<radio id="selectedframeRadio"
|
||||
label="&selectedframeRadio.label;"
|
||||
accesskey="&selectedframeRadio.accesskey;"/>
|
||||
<radio id="eachframesepRadio"
|
||||
label="&eachframesepRadio.label;"
|
||||
accesskey="&eachframesepRadio.accesskey;"/>
|
||||
</radiogroup>
|
||||
</groupbox>
|
||||
|
||||
<!-- used to store titles and labels -->
|
||||
<data style="display:none;" id="printButton" label="&printButton.label;"/>
|
||||
<data style="display:none;" id="fpDialog" label="&fpDialog.title;"/>
|
||||
|
||||
</dialog>
|
||||
|
@ -1,373 +0,0 @@
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var dialog;
|
||||
var gPrintBundle;
|
||||
var gPrintSettings = null;
|
||||
var gPrintSettingsInterface = Components.interfaces.nsIPrintSettings;
|
||||
var gPaperArray;
|
||||
var gPrefs;
|
||||
var gParamBlock;
|
||||
|
||||
var gPrintSetInterface = Components.interfaces.nsIPrintSettings;
|
||||
var doDebug = true;
|
||||
|
||||
// ---------------------------------------------------
|
||||
function checkDouble(element, maxVal) {
|
||||
var value = element.value;
|
||||
if (value && value.length > 0) {
|
||||
value = value.replace(/[^\.|^0-9]/g, "");
|
||||
if (!value) {
|
||||
element.value = "";
|
||||
} else if (value > maxVal) {
|
||||
element.value = maxVal;
|
||||
} else {
|
||||
element.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function isListOfPrinterFeaturesAvailable() {
|
||||
return gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".has_special_printerfeatures", false);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function getDoubleStr(val, dec) {
|
||||
var str = val.toString();
|
||||
var inx = str.indexOf(".");
|
||||
return str.substring(0, inx + dec + 1);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function initDialog() {
|
||||
gPrintBundle = document.getElementById("printBundle");
|
||||
|
||||
dialog = {};
|
||||
|
||||
dialog.paperList = document.getElementById("paperList");
|
||||
dialog.paperGroup = document.getElementById("paperGroup");
|
||||
|
||||
dialog.jobTitleLabel = document.getElementById("jobTitleLabel");
|
||||
dialog.jobTitleGroup = document.getElementById("jobTitleGroup");
|
||||
dialog.jobTitleInput = document.getElementById("jobTitleInput");
|
||||
|
||||
dialog.colorGroup = document.getElementById("colorGroup");
|
||||
dialog.colorRadioGroup = document.getElementById("colorRadioGroup");
|
||||
dialog.colorRadio = document.getElementById("colorRadio");
|
||||
dialog.grayRadio = document.getElementById("grayRadio");
|
||||
|
||||
dialog.topInput = document.getElementById("topInput");
|
||||
dialog.bottomInput = document.getElementById("bottomInput");
|
||||
dialog.leftInput = document.getElementById("leftInput");
|
||||
dialog.rightInput = document.getElementById("rightInput");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function round10(val) {
|
||||
return Math.round(val * 10) / 10;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------
|
||||
function paperListElement(aPaperListElement) {
|
||||
this.paperListElement = aPaperListElement;
|
||||
}
|
||||
|
||||
paperListElement.prototype =
|
||||
{
|
||||
clearPaperList() {
|
||||
// remove the menupopup node child of the menulist.
|
||||
this.paperListElement.firstChild.remove();
|
||||
},
|
||||
|
||||
appendPaperNames(aDataObject) {
|
||||
var popupNode = document.createElement("menupopup");
|
||||
for (var i = 0;i < aDataObject.length;i++) {
|
||||
var paperObj = aDataObject[i];
|
||||
var itemNode = document.createElement("menuitem");
|
||||
var label;
|
||||
try {
|
||||
label = gPrintBundle.getString(paperObj.name);
|
||||
} catch (e) {
|
||||
/* No name in string bundle ? Then build one manually (this
|
||||
* usually happens when gPaperArray was build by createPaperArrayFromPrinterFeatures() ...) */
|
||||
if (paperObj.inches) {
|
||||
label = paperObj.name + " (" + round10(paperObj.width) + "x" + round10(paperObj.height) + " inch)";
|
||||
} else {
|
||||
label = paperObj.name + " (" + paperObj.width + "x" + paperObj.height + " mm)";
|
||||
}
|
||||
}
|
||||
itemNode.setAttribute("label", label);
|
||||
itemNode.setAttribute("value", i);
|
||||
popupNode.appendChild(itemNode);
|
||||
}
|
||||
this.paperListElement.appendChild(popupNode);
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------
|
||||
function createPaperArrayFromDefaults() {
|
||||
var paperNames = ["letterSize", "legalSize", "exectiveSize", "a5Size", "a4Size", "a3Size", "a2Size", "a1Size", "a0Size"];
|
||||
// var paperNames = ["&letterRadio.label;", "&legalRadio.label;", "&exectiveRadio.label;", "&a4Radio.label;", "&a3Radio.label;"];
|
||||
var paperWidths = [ 8.5, 8.5, 7.25, 148.0, 210.0, 287.0, 420.0, 594.0, 841.0];
|
||||
var paperHeights = [11.0, 14.0, 10.50, 210.0, 297.0, 420.0, 594.0, 841.0, 1189.0];
|
||||
var paperInches = [true, true, true, false, false, false, false, false, false];
|
||||
|
||||
gPaperArray = [];
|
||||
|
||||
for (var i = 0;i < paperNames.length;i++) {
|
||||
var obj = {};
|
||||
obj.name = paperNames[i];
|
||||
obj.width = paperWidths[i];
|
||||
obj.height = paperHeights[i];
|
||||
obj.inches = paperInches[i];
|
||||
|
||||
/* Calculate the width/height in millimeters */
|
||||
if (paperInches[i]) {
|
||||
obj.width_mm = paperWidths[i] * 25.4;
|
||||
obj.height_mm = paperHeights[i] * 25.4;
|
||||
} else {
|
||||
obj.width_mm = paperWidths[i];
|
||||
obj.height_mm = paperHeights[i];
|
||||
}
|
||||
gPaperArray[i] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function createPaperArrayFromPrinterFeatures() {
|
||||
var printername = gPrintSettings.printerName;
|
||||
if (doDebug) {
|
||||
dump("createPaperArrayFromPrinterFeatures for " + printername + ".\n");
|
||||
}
|
||||
|
||||
gPaperArray = [];
|
||||
|
||||
var numPapers = gPrefs.getIntPref("print.tmp.printerfeatures." + printername + ".paper.count");
|
||||
|
||||
if (doDebug) {
|
||||
dump("processing " + numPapers + " entries...\n");
|
||||
}
|
||||
|
||||
for (var i = 0;i < numPapers;i++) {
|
||||
var obj = {};
|
||||
obj.name = gPrefs.getCharPref("print.tmp.printerfeatures." + printername + ".paper." + i + ".name");
|
||||
obj.width_mm = gPrefs.getIntPref("print.tmp.printerfeatures." + printername + ".paper." + i + ".width_mm");
|
||||
obj.height_mm = gPrefs.getIntPref("print.tmp.printerfeatures." + printername + ".paper." + i + ".height_mm");
|
||||
obj.inches = gPrefs.getBoolPref("print.tmp.printerfeatures." + printername + ".paper." + i + ".is_inch");
|
||||
|
||||
/* Calculate the width/height in paper's native units (either inches or millimeters) */
|
||||
if (obj.inches) {
|
||||
obj.width = obj.width_mm / 25.4;
|
||||
obj.height = obj.height_mm / 25.4;
|
||||
} else {
|
||||
obj.width = obj.width_mm;
|
||||
obj.height = obj.height_mm;
|
||||
}
|
||||
|
||||
gPaperArray[i] = obj;
|
||||
|
||||
if (doDebug) {
|
||||
dump("paper index=" + i + ", name=" + obj.name + ", width=" + obj.width + ", height=" + obj.height + ".\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function createPaperArray() {
|
||||
if (isListOfPrinterFeaturesAvailable()) {
|
||||
createPaperArrayFromPrinterFeatures();
|
||||
} else {
|
||||
createPaperArrayFromDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function createPaperSizeList(selectedInx) {
|
||||
var selectElement = new paperListElement(dialog.paperList);
|
||||
selectElement.clearPaperList();
|
||||
|
||||
selectElement.appendPaperNames(gPaperArray);
|
||||
|
||||
if (selectedInx > -1) {
|
||||
selectElement.paperListElement.selectedIndex = selectedInx;
|
||||
}
|
||||
|
||||
// dialog.paperList = selectElement;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function loadDialog() {
|
||||
var print_paper_unit = 0;
|
||||
var print_paper_width = 0.0;
|
||||
var print_paper_height = 0.0;
|
||||
var print_paper_name = "";
|
||||
var print_color = true;
|
||||
var print_jobtitle = "";
|
||||
|
||||
gPrefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
|
||||
|
||||
if (gPrintSettings) {
|
||||
print_paper_unit = gPrintSettings.paperSizeUnit;
|
||||
print_paper_width = gPrintSettings.paperWidth;
|
||||
print_paper_height = gPrintSettings.paperHeight;
|
||||
print_paper_name = gPrintSettings.paperName;
|
||||
print_color = gPrintSettings.printInColor;
|
||||
print_jobtitle = gPrintSettings.title;
|
||||
}
|
||||
|
||||
if (doDebug) {
|
||||
dump("loadDialog******************************\n");
|
||||
dump("paperSizeType " + print_paper_unit + "\n");
|
||||
dump("paperWidth " + print_paper_width + "\n");
|
||||
dump("paperHeight " + print_paper_height + "\n");
|
||||
dump("paperName " + print_paper_name + "\n");
|
||||
dump("print_color " + print_color + "\n");
|
||||
dump("print_jobtitle " + print_jobtitle + "\n");
|
||||
}
|
||||
|
||||
createPaperArray();
|
||||
|
||||
var paperSelectedInx = 0;
|
||||
for (var i = 0;i < gPaperArray.length;i++) {
|
||||
if (print_paper_name == gPaperArray[i].name) {
|
||||
paperSelectedInx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDebug) {
|
||||
if (i == gPaperArray.length)
|
||||
dump("loadDialog: No paper found.\n");
|
||||
else
|
||||
dump("loadDialog: found paper '" + gPaperArray[paperSelectedInx].name + "'.\n");
|
||||
}
|
||||
|
||||
createPaperSizeList(paperSelectedInx);
|
||||
|
||||
/* Enable/disable and/or hide/unhide widgets based in the information
|
||||
* whether the selected printer and/or print module supports the matching
|
||||
* feature or not */
|
||||
if (isListOfPrinterFeaturesAvailable()) {
|
||||
// job title
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".can_change_jobtitle"))
|
||||
dialog.jobTitleInput.removeAttribute("disabled");
|
||||
else
|
||||
dialog.jobTitleInput.setAttribute("disabled", "true");
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".supports_jobtitle_change"))
|
||||
dialog.jobTitleGroup.removeAttribute("hidden");
|
||||
else
|
||||
dialog.jobTitleGroup.setAttribute("hidden", "true");
|
||||
|
||||
// paper size
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".can_change_paper_size"))
|
||||
dialog.paperList.removeAttribute("disabled");
|
||||
else
|
||||
dialog.paperList.setAttribute("disabled", "true");
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".supports_paper_size_change"))
|
||||
dialog.paperGroup.removeAttribute("hidden");
|
||||
else
|
||||
dialog.paperGroup.setAttribute("hidden", "true");
|
||||
|
||||
// color/grayscale radio
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".can_change_printincolor"))
|
||||
dialog.colorRadioGroup.removeAttribute("disabled");
|
||||
else
|
||||
dialog.colorRadioGroup.setAttribute("disabled", "true");
|
||||
if (gPrefs.getBoolPref("print.tmp.printerfeatures." + gPrintSettings.printerName + ".supports_printincolor_change"))
|
||||
dialog.colorGroup.removeAttribute("hidden");
|
||||
else
|
||||
dialog.colorGroup.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
if (print_color) {
|
||||
dialog.colorRadioGroup.selectedItem = dialog.colorRadio;
|
||||
} else {
|
||||
dialog.colorRadioGroup.selectedItem = dialog.grayRadio;
|
||||
}
|
||||
|
||||
dialog.jobTitleInput.value = print_jobtitle;
|
||||
|
||||
dialog.topInput.value = gPrintSettings.edgeTop.toFixed(2);
|
||||
dialog.bottomInput.value = gPrintSettings.edgeBottom.toFixed(2);
|
||||
dialog.leftInput.value = gPrintSettings.edgeLeft.toFixed(2);
|
||||
dialog.rightInput.value = gPrintSettings.edgeRight.toFixed(2);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function onLoad() {
|
||||
// Init dialog.
|
||||
initDialog();
|
||||
|
||||
gPrintSettings = window.arguments[0].QueryInterface(gPrintSetInterface);
|
||||
gParamBlock = window.arguments[1].QueryInterface(Components.interfaces.nsIDialogParamBlock);
|
||||
|
||||
if (doDebug) {
|
||||
if (gPrintSettings == null) alert("PrintSettings is null!");
|
||||
if (gParamBlock == null) alert("nsIDialogParam is null!");
|
||||
}
|
||||
|
||||
// default return value is "cancel"
|
||||
gParamBlock.SetInt(0, 0);
|
||||
|
||||
loadDialog();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
function onAccept() {
|
||||
var print_paper_unit = gPrintSettingsInterface.kPaperSizeInches;
|
||||
var print_paper_width = 0.0;
|
||||
var print_paper_height = 0.0;
|
||||
var print_paper_name = "";
|
||||
|
||||
if (gPrintSettings != null) {
|
||||
var paperSelectedInx = dialog.paperList.selectedIndex;
|
||||
if (gPaperArray[paperSelectedInx].inches) {
|
||||
print_paper_unit = gPrintSettingsInterface.kPaperSizeInches;
|
||||
} else {
|
||||
print_paper_unit = gPrintSettingsInterface.kPaperSizeMillimeters;
|
||||
}
|
||||
print_paper_width = gPaperArray[paperSelectedInx].width;
|
||||
print_paper_height = gPaperArray[paperSelectedInx].height;
|
||||
print_paper_name = gPaperArray[paperSelectedInx].name;
|
||||
|
||||
gPrintSettings.paperSizeUnit = print_paper_unit;
|
||||
gPrintSettings.paperWidth = print_paper_width;
|
||||
gPrintSettings.paperHeight = print_paper_height;
|
||||
gPrintSettings.paperName = print_paper_name;
|
||||
|
||||
// save these out so they can be picked up by the device spec
|
||||
gPrintSettings.printInColor = dialog.colorRadio.selected;
|
||||
gPrintSettings.title = dialog.jobTitleInput.value;
|
||||
|
||||
gPrintSettings.edgeTop = dialog.topInput.value;
|
||||
gPrintSettings.edgeBottom = dialog.bottomInput.value;
|
||||
gPrintSettings.edgeLeft = dialog.leftInput.value;
|
||||
gPrintSettings.edgeRight = dialog.rightInput.value;
|
||||
|
||||
if (doDebug) {
|
||||
dump("onAccept******************************\n");
|
||||
dump("paperSizeUnit " + print_paper_unit + "\n");
|
||||
dump("paperWidth " + print_paper_width + "\n");
|
||||
dump("paperHeight " + print_paper_height + "\n");
|
||||
dump("paperName '" + print_paper_name + "'\n");
|
||||
|
||||
dump("printInColor " + gPrintSettings.printInColor + "\n");
|
||||
}
|
||||
} else {
|
||||
dump("************ onAccept gPrintSettings: " + gPrintSettings + "\n");
|
||||
}
|
||||
|
||||
if (gParamBlock) {
|
||||
// set return value to "ok"
|
||||
gParamBlock.SetInt(0, 1);
|
||||
} else {
|
||||
dump("*** FATAL ERROR: paramBlock missing\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<!DOCTYPE dialog SYSTEM "chrome://global/locale/printjoboptions.dtd">
|
||||
|
||||
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="onLoad();"
|
||||
ondialogaccept="return onAccept();"
|
||||
title="&printJobOptions.title;"
|
||||
persist="screenX screenY"
|
||||
screenX="24" screenY="24">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/printjoboptions.js"/>
|
||||
|
||||
<stringbundle id="printBundle" src="chrome://global/locale/printPageSetup.properties"/>
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
<column flex="1"/>
|
||||
</columns>
|
||||
|
||||
<rows>
|
||||
<row id="jobTitleGroup">
|
||||
<hbox align="center" pack="end">
|
||||
<label id="jobTitleLabel"
|
||||
value="&jobTitleInput.label;"
|
||||
accesskey="&jobTitleInput.accesskey;"
|
||||
control="jobTitleInput"/>
|
||||
</hbox>
|
||||
<textbox id="jobTitleInput" flex="1"/>
|
||||
</row>
|
||||
|
||||
<row id="paperGroup">
|
||||
<hbox align="center" pack="end">
|
||||
<label id="paperLabel"
|
||||
value="&paperInput.label;"
|
||||
accesskey="&paperInput.accesskey;"
|
||||
control="paperList"/>
|
||||
</hbox>
|
||||
<menulist id="paperList" flex="1">
|
||||
<menupopup/>
|
||||
</menulist>
|
||||
</row>
|
||||
|
||||
<row id="colorGroup">
|
||||
<hbox align="center" pack="end">
|
||||
<label control="colorRadioGroup" value="&colorGroup.label;"/>
|
||||
</hbox>
|
||||
<radiogroup id="colorRadioGroup" orient="horizontal">
|
||||
<radio id="grayRadio"
|
||||
label="&grayRadio.label;"
|
||||
accesskey="&grayRadio.accesskey;"/>
|
||||
<radio id="colorRadio"
|
||||
label="&colorRadio.label;"
|
||||
accesskey="&colorRadio.accesskey;"/>
|
||||
</radiogroup>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
<grid>
|
||||
<columns>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<groupbox flex="1">
|
||||
<caption label="&edgeMarginInput.label;"/>
|
||||
<hbox>
|
||||
<hbox align="center">
|
||||
<label id="topLabel"
|
||||
value="&topInput.label;"
|
||||
accesskey="&topInput.accesskey;"
|
||||
control="topInput"/>
|
||||
<textbox id="topInput" style="width:5em;" onkeyup="checkDouble(this, 0.5)"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<label id="bottomLabel"
|
||||
value="&bottomInput.label;"
|
||||
accesskey="&bottomInput.accesskey;"
|
||||
control="bottomInput"/>
|
||||
<textbox id="bottomInput" style="width:5em;" onkeyup="checkDouble(this, 0.5)"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<label id="leftLabel"
|
||||
value="&leftInput.label;"
|
||||
accesskey="&leftInput.accesskey;"
|
||||
control="leftInput"/>
|
||||
<textbox id="leftInput" style="width:5em;" onkeyup="checkDouble(this, 0.5)"/>
|
||||
</hbox>
|
||||
<hbox align="center">
|
||||
<label id="rightLabel"
|
||||
value="&rightInput.label;"
|
||||
accesskey="&rightInput.accesskey;"
|
||||
control="rightInput"/>
|
||||
<textbox id="rightInput" style="width:5em;" onkeyup="checkDouble(this, 0.5)"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
</row>
|
||||
|
||||
</rows>
|
||||
</grid>
|
||||
|
||||
</dialog>
|
@ -4,14 +4,10 @@
|
||||
|
||||
toolkit.jar:
|
||||
#ifndef XP_MACOSX
|
||||
#ifdef XP_UNIX
|
||||
content/global/printdialog.js (content/printdialog.js)
|
||||
content/global/printdialog.xul (content/printdialog.xul)
|
||||
content/global/printjoboptions.js (content/printjoboptions.js)
|
||||
content/global/printjoboptions.xul (content/printjoboptions.xul)
|
||||
#endif
|
||||
#ifdef XP_WIN
|
||||
content/global/printPageSetup.js (content/printPageSetup.js)
|
||||
content/global/printPageSetup.xul (content/printPageSetup.xul)
|
||||
#endif
|
||||
content/global/printPreviewProgress.js (content/printPreviewProgress.js)
|
||||
content/global/printPreviewProgress.xul (content/printPreviewProgress.xul)
|
||||
content/global/printProgress.js (content/printProgress.js)
|
||||
|
@ -188,14 +188,6 @@ nsPrintingProxy::ShowPageSetup(mozIDOMWindowProxy *parent,
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintingProxy::ShowPrinterProperties(mozIDOMWindowProxy *parent,
|
||||
const char16_t *printerName,
|
||||
nsIPrintSettings *printSettings)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrintingProxy::SavePrintSettings(nsIPrintSettings* aPS,
|
||||
bool aUsePrinterNamePrefix,
|
||||
|
@ -72,12 +72,6 @@ nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent, nsIPrintSetti
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent, const char16_t *printerName, nsIPrintSettings *printSettings)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// nsPrintingPromptService::nsIWebProgressListener
|
||||
|
@ -5,9 +5,6 @@
|
||||
|
||||
#include "nsPrintingPromptService.h"
|
||||
|
||||
#include "nsArray.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIDialogParamBlock.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
@ -18,40 +15,8 @@
|
||||
#include "nsPrintProgress.h"
|
||||
#include "nsPrintProgressParams.h"
|
||||
|
||||
static const char *kPrintDialogURL = "chrome://global/content/printdialog.xul";
|
||||
static const char *kPrintProgressDialogURL = "chrome://global/content/printProgress.xul";
|
||||
static const char *kPrtPrvProgressDialogURL = "chrome://global/content/printPreviewProgress.xul";
|
||||
static const char *kPageSetupDialogURL = "chrome://global/content/printPageSetup.xul";
|
||||
static const char *kPrinterPropertiesURL = "chrome://global/content/printjoboptions.xul";
|
||||
|
||||
/****************************************************************
|
||||
************************* ParamBlock ***************************
|
||||
****************************************************************/
|
||||
|
||||
class ParamBlock {
|
||||
|
||||
public:
|
||||
ParamBlock()
|
||||
{
|
||||
mBlock = 0;
|
||||
}
|
||||
~ParamBlock()
|
||||
{
|
||||
NS_IF_RELEASE(mBlock);
|
||||
}
|
||||
nsresult Init() {
|
||||
return CallCreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID, &mBlock);
|
||||
}
|
||||
nsIDialogParamBlock * operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mBlock; }
|
||||
operator nsIDialogParamBlock * () const { return mBlock; }
|
||||
|
||||
private:
|
||||
nsIDialogParamBlock *mBlock;
|
||||
};
|
||||
|
||||
/****************************************************************
|
||||
***************** nsPrintingPromptService **********************
|
||||
****************************************************************/
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPrintingPromptService, nsIPrintingPromptService, nsIWebProgressListener)
|
||||
|
||||
@ -79,21 +44,13 @@ nsPrintingPromptService::ShowPrintDialog(mozIDOMWindowProxy *parent,
|
||||
NS_ENSURE_ARG(webBrowserPrint);
|
||||
NS_ENSURE_ARG(printSettings);
|
||||
|
||||
// Try to access a component dialog
|
||||
nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
|
||||
NS_PRINTDIALOGSERVICE_CONTRACTID));
|
||||
if (dlgPrint)
|
||||
return dlgPrint->Show(nsPIDOMWindowOuter::From(parent),
|
||||
printSettings, webBrowserPrint);
|
||||
|
||||
// Show the built-in dialog instead
|
||||
ParamBlock block;
|
||||
nsresult rv = block.Init();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
block->SetInt(0, 0);
|
||||
return DoDialog(parent, block, webBrowserPrint, printSettings, kPrintDialogURL);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -143,110 +100,15 @@ nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent,
|
||||
{
|
||||
NS_ENSURE_ARG(printSettings);
|
||||
|
||||
// Try to access a component dialog
|
||||
nsCOMPtr<nsIPrintDialogService> dlgPrint(do_GetService(
|
||||
NS_PRINTDIALOGSERVICE_CONTRACTID));
|
||||
if (dlgPrint)
|
||||
return dlgPrint->ShowPageSetup(nsPIDOMWindowOuter::From(parent),
|
||||
printSettings);
|
||||
|
||||
ParamBlock block;
|
||||
nsresult rv = block.Init();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
block->SetInt(0, 0);
|
||||
return DoDialog(parent, block, nullptr, printSettings, kPageSetupDialogURL);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent,
|
||||
const char16_t *printerName,
|
||||
nsIPrintSettings *printSettings)
|
||||
{
|
||||
/* fixme: We simply ignore the |aPrinter| argument here
|
||||
* We should get the supported printer attributes from the printer and
|
||||
* populate the print job options dialog with these data instead of using
|
||||
* the "default set" here.
|
||||
* However, this requires changes on all platforms and is another big chunk
|
||||
* of patches ... ;-(
|
||||
*/
|
||||
NS_ENSURE_ARG(printerName);
|
||||
NS_ENSURE_ARG(printSettings);
|
||||
|
||||
ParamBlock block;
|
||||
nsresult rv = block.Init();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
block->SetInt(0, 0);
|
||||
return DoDialog(parent, block, nullptr, printSettings, kPrinterPropertiesURL);
|
||||
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrintingPromptService::DoDialog(mozIDOMWindowProxy *aParent,
|
||||
nsIDialogParamBlock *aParamBlock,
|
||||
nsIWebBrowserPrint *aWebBrowserPrint,
|
||||
nsIPrintSettings* aPS,
|
||||
const char *aChromeURL)
|
||||
{
|
||||
NS_ENSURE_ARG(aParamBlock);
|
||||
NS_ENSURE_ARG(aPS);
|
||||
NS_ENSURE_ARG(aChromeURL);
|
||||
|
||||
if (!mWatcher)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// get a parent, if at all possible
|
||||
// (though we'd rather this didn't fail, it's OK if it does. so there's
|
||||
// no failure or null check.)
|
||||
nsCOMPtr<mozIDOMWindowProxy> activeParent;
|
||||
if (!aParent)
|
||||
{
|
||||
mWatcher->GetActiveWindow(getter_AddRefs(activeParent));
|
||||
aParent = activeParent;
|
||||
}
|
||||
|
||||
// create a nsIMutableArray of the parameters
|
||||
// being passed to the window
|
||||
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
|
||||
|
||||
nsCOMPtr<nsISupports> psSupports(do_QueryInterface(aPS));
|
||||
NS_ASSERTION(psSupports, "PrintSettings must be a supports");
|
||||
array->AppendElement(psSupports);
|
||||
|
||||
if (aWebBrowserPrint) {
|
||||
nsCOMPtr<nsISupports> wbpSupports(do_QueryInterface(aWebBrowserPrint));
|
||||
NS_ASSERTION(wbpSupports, "nsIWebBrowserPrint must be a supports");
|
||||
array->AppendElement(wbpSupports);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> blkSupps(do_QueryInterface(aParamBlock));
|
||||
NS_ASSERTION(blkSupps, "IOBlk must be a supports");
|
||||
array->AppendElement(blkSupps);
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> dialog;
|
||||
nsresult rv = mWatcher->OpenWindow(aParent, aChromeURL, "_blank",
|
||||
"centerscreen,chrome,modal,titlebar", array,
|
||||
getter_AddRefs(dialog));
|
||||
|
||||
// if aWebBrowserPrint is not null then we are printing
|
||||
// so we want to pass back NS_ERROR_ABORT on cancel
|
||||
if (NS_SUCCEEDED(rv) && aWebBrowserPrint)
|
||||
{
|
||||
int32_t status;
|
||||
aParamBlock->GetInt(0, &status);
|
||||
return status == 0?NS_ERROR_ABORT:NS_OK;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// nsIWebProgressListener
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintingPromptService::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, uint32_t aStateFlags, nsresult aStatus)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@
|
||||
|
||||
// Printing Progress Includes
|
||||
#include "nsPrintProgress.h"
|
||||
#include "nsPrintProgressParams.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
|
||||
class nsIDOMWindow;
|
||||
@ -43,12 +42,6 @@ protected:
|
||||
virtual ~nsPrintingPromptService();
|
||||
|
||||
private:
|
||||
nsresult DoDialog(mozIDOMWindowProxy *aParent,
|
||||
nsIDialogParamBlock *aParamBlock,
|
||||
nsIWebBrowserPrint *aWebBrowserPrint,
|
||||
nsIPrintSettings* aPS,
|
||||
const char *aChromeURL);
|
||||
|
||||
nsCOMPtr<nsIWindowWatcher> mWatcher;
|
||||
nsCOMPtr<nsIPrintProgress> mPrintProgress;
|
||||
nsCOMPtr<nsIWebProgressListener> mWebProgressListener;
|
||||
|
@ -116,12 +116,6 @@ nsPrintingPromptService::ShowPageSetup(mozIDOMWindowProxy *parent, nsIPrintSetti
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrintingPromptService::ShowPrinterProperties(mozIDOMWindowProxy *parent, const char16_t *printerName, nsIPrintSettings *printSettings)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// nsIWebProgressListener
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -1,44 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- extracted from printdialog.xul -->
|
||||
|
||||
<!ENTITY printButton.label "Print">
|
||||
|
||||
<!ENTITY printDialog.title "Print">
|
||||
|
||||
<!ENTITY fpDialog.title "Save File">
|
||||
|
||||
<!ENTITY fileCheck.label "Print to File">
|
||||
<!ENTITY fileCheck.accesskey "F">
|
||||
<!ENTITY propertiesButton.label "Properties…">
|
||||
<!ENTITY propertiesButton.accesskey "o">
|
||||
<!ENTITY descText.label "Printer Description:">
|
||||
<!ENTITY printer.label "Printer">
|
||||
<!ENTITY printerInput.label "Printer Name:">
|
||||
<!ENTITY printerInput.accesskey "N">
|
||||
|
||||
<!ENTITY printrangeGroup.label "Print Range">
|
||||
<!ENTITY allpagesRadio.label "All Pages">
|
||||
<!ENTITY allpagesRadio.accesskey "A">
|
||||
<!ENTITY rangeRadio.label "Pages">
|
||||
<!ENTITY rangeRadio.accesskey "P">
|
||||
<!ENTITY frompageInput.label "from">
|
||||
<!ENTITY frompageInput.accesskey "r">
|
||||
<!ENTITY topageInput.label "to">
|
||||
<!ENTITY topageInput.accesskey "t">
|
||||
<!ENTITY selectionRadio.label "Selection">
|
||||
<!ENTITY selectionRadio.accesskey "S">
|
||||
|
||||
<!ENTITY copies.label "Copies">
|
||||
<!ENTITY numCopies.label "Number of copies:">
|
||||
<!ENTITY numCopies.accesskey "c">
|
||||
|
||||
<!ENTITY printframeGroup.label "Print Frames">
|
||||
<!ENTITY aslaidoutRadio.label "As laid out on the screen">
|
||||
<!ENTITY aslaidoutRadio.accesskey "u">
|
||||
<!ENTITY selectedframeRadio.label "The selected frame">
|
||||
<!ENTITY selectedframeRadio.accesskey "m">
|
||||
<!ENTITY eachframesepRadio.label "Each frame separately">
|
||||
<!ENTITY eachframesepRadio.accesskey "E">
|
@ -1,29 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- extracted from printjoboptions.xul -->
|
||||
|
||||
<!ENTITY printJobOptions.title "Printer Properties">
|
||||
|
||||
<!ENTITY paperInput.label "Paper Size:">
|
||||
<!ENTITY paperInput.accesskey "P">
|
||||
|
||||
<!ENTITY jobTitleInput.label "Job Title:">
|
||||
<!ENTITY jobTitleInput.accesskey "J">
|
||||
|
||||
<!ENTITY colorGroup.label "Color:">
|
||||
<!ENTITY grayRadio.label "Grayscale">
|
||||
<!ENTITY grayRadio.accesskey "G">
|
||||
<!ENTITY colorRadio.label "Color">
|
||||
<!ENTITY colorRadio.accesskey "C">
|
||||
|
||||
<!ENTITY edgeMarginInput.label "Gap from edge of paper to Margin">
|
||||
<!ENTITY topInput.label "Top:">
|
||||
<!ENTITY topInput.accesskey "T">
|
||||
<!ENTITY bottomInput.label "Bottom:">
|
||||
<!ENTITY bottomInput.accesskey "B">
|
||||
<!ENTITY leftInput.label "Left:">
|
||||
<!ENTITY leftInput.accesskey "L">
|
||||
<!ENTITY rightInput.label "Right:">
|
||||
<!ENTITY rightInput.accesskey "R">
|
@ -70,9 +70,9 @@
|
||||
locale/@AB_CD@/global/notification.dtd (%chrome/global/notification.dtd)
|
||||
locale/@AB_CD@/global/preferences.dtd (%chrome/global/preferences.dtd)
|
||||
#ifndef MOZ_FENNEC
|
||||
locale/@AB_CD@/global/printdialog.dtd (%chrome/global/printdialog.dtd)
|
||||
locale/@AB_CD@/global/printjoboptions.dtd (%chrome/global/printjoboptions.dtd)
|
||||
#ifndef MOZ_GTK
|
||||
locale/@AB_CD@/global/printPageSetup.dtd (%chrome/global/printPageSetup.dtd)
|
||||
#endif
|
||||
locale/@AB_CD@/global/printPreview.dtd (%chrome/global/printPreview.dtd)
|
||||
locale/@AB_CD@/global/printPreviewProgress.dtd (%chrome/global/printPreviewProgress.dtd)
|
||||
locale/@AB_CD@/global/printdialog.properties (%chrome/global/printdialog.properties)
|
||||
|
@ -24,7 +24,6 @@ toolkit.jar:
|
||||
skin/classic/global/numberbox.css
|
||||
skin/classic/global/popup.css
|
||||
skin/classic/global/preferences.css
|
||||
skin/classic/global/printPageSetup.css
|
||||
skin/classic/global/printPreview.css
|
||||
skin/classic/global/radio.css
|
||||
skin/classic/global/scrollbox.css
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
#include "prlink.h"
|
||||
#endif
|
||||
|
||||
#define FREEDESKTOP_SCREENSAVER_TARGET "org.freedesktop.ScreenSaver"
|
||||
#define FREEDESKTOP_SCREENSAVER_OBJECT "/ScreenSaver"
|
||||
#define FREEDESKTOP_SCREENSAVER_INTERFACE "org.freedesktop.ScreenSaver"
|
||||
@ -32,6 +36,9 @@ StaticRefPtr<WakeLockListener> WakeLockListener::sSingleton;
|
||||
enum DesktopEnvironment {
|
||||
FreeDesktop,
|
||||
GNOME,
|
||||
#if defined(MOZ_X11)
|
||||
XScreenSaver,
|
||||
#endif
|
||||
Unsupported,
|
||||
};
|
||||
|
||||
@ -59,6 +66,11 @@ private:
|
||||
bool SendGNOMEInhibitMessage();
|
||||
bool SendMessage(DBusMessage* aMessage);
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
static bool CheckXScreenSaverSupport();
|
||||
static bool InhibitXScreenSaver(bool inhibit);
|
||||
#endif
|
||||
|
||||
static void ReceiveInhibitReply(DBusPendingCall* aPending, void* aUserData);
|
||||
void InhibitFailed();
|
||||
void InhibitSucceeded(uint32_t aInhibitRequest);
|
||||
@ -143,6 +155,71 @@ WakeLockTopic::SendGNOMEInhibitMessage()
|
||||
}
|
||||
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
|
||||
typedef Bool (*_XScreenSaverQueryExtension_fn)(Display* dpy, int* event_base,
|
||||
int* error_base);
|
||||
typedef Bool (*_XScreenSaverQueryVersion_fn)(Display* dpy, int* major,
|
||||
int* minor);
|
||||
typedef void (*_XScreenSaverSuspend_fn)(Display* dpy, Bool suspend);
|
||||
|
||||
static PRLibrary* sXssLib = nullptr;
|
||||
static _XScreenSaverQueryExtension_fn _XSSQueryExtension = nullptr;
|
||||
static _XScreenSaverQueryVersion_fn _XSSQueryVersion = nullptr;
|
||||
static _XScreenSaverSuspend_fn _XSSSuspend = nullptr;
|
||||
|
||||
/* static */ bool
|
||||
WakeLockTopic::CheckXScreenSaverSupport()
|
||||
{
|
||||
if (!sXssLib) {
|
||||
sXssLib = PR_LoadLibrary("libXss.so.1");
|
||||
if (!sXssLib) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_XSSQueryExtension = (_XScreenSaverQueryExtension_fn)
|
||||
PR_FindFunctionSymbol(sXssLib, "XScreenSaverQueryExtension");
|
||||
_XSSQueryVersion = (_XScreenSaverQueryVersion_fn)
|
||||
PR_FindFunctionSymbol(sXssLib, "XScreenSaverQueryVersion");
|
||||
_XSSSuspend = (_XScreenSaverSuspend_fn)
|
||||
PR_FindFunctionSymbol(sXssLib, "XScreenSaverSuspend");
|
||||
if (!_XSSQueryExtension || !_XSSQueryVersion || !_XSSSuspend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GdkDisplay* gDisplay = gdk_display_get_default();
|
||||
if (!GDK_IS_X11_DISPLAY(gDisplay)) return false;
|
||||
Display* display = GDK_DISPLAY_XDISPLAY(gDisplay);
|
||||
|
||||
int throwaway;
|
||||
if (!_XSSQueryExtension(display, &throwaway, &throwaway)) return false;
|
||||
|
||||
int major, minor;
|
||||
if (!_XSSQueryVersion(display, &major, &minor)) return false;
|
||||
// Needs to be compatible with version 1.1
|
||||
if (major != 1) return false;
|
||||
if (minor < 1) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WakeLockTopic::InhibitXScreenSaver(bool inhibit)
|
||||
{
|
||||
// Should only be called if CheckXScreenSaverSupport returns true.
|
||||
// There's a couple of safety checks here nonetheless.
|
||||
if (!_XSSSuspend) return false;
|
||||
GdkDisplay* gDisplay = gdk_display_get_default();
|
||||
if (!GDK_IS_X11_DISPLAY(gDisplay)) return false;
|
||||
Display* display = GDK_DISPLAY_XDISPLAY(gDisplay);
|
||||
_XSSSuspend(display, inhibit);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
bool
|
||||
WakeLockTopic::SendInhibit()
|
||||
{
|
||||
@ -156,6 +233,10 @@ WakeLockTopic::SendInhibit()
|
||||
case GNOME:
|
||||
sendOk = SendGNOMEInhibitMessage();
|
||||
break;
|
||||
#if defined(MOZ_X11)
|
||||
case XScreenSaver:
|
||||
return InhibitXScreenSaver(true);
|
||||
#endif
|
||||
case Unsupported:
|
||||
return false;
|
||||
}
|
||||
@ -185,6 +266,11 @@ WakeLockTopic::SendUninhibit()
|
||||
SESSION_MANAGER_INTERFACE,
|
||||
"Uninhibit"));
|
||||
}
|
||||
#if defined(MOZ_X11)
|
||||
else if (mDesktopEnvironment == XScreenSaver) {
|
||||
return InhibitXScreenSaver(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!message) {
|
||||
return false;
|
||||
@ -249,8 +335,11 @@ WakeLockTopic::InhibitFailed()
|
||||
|
||||
if (mDesktopEnvironment == FreeDesktop) {
|
||||
mDesktopEnvironment = GNOME;
|
||||
#if defined(MOZ_X11)
|
||||
} else if (mDesktopEnvironment == GNOME && CheckXScreenSaverSupport()) {
|
||||
mDesktopEnvironment = XScreenSaver;
|
||||
#endif
|
||||
} else {
|
||||
NS_ASSERTION(mDesktopEnvironment == GNOME, "Unknown desktop environment");
|
||||
mDesktopEnvironment = Unsupported;
|
||||
mShouldInhibit = false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user