Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-08-30 22:09:02 -04:00
commit 5dac9823cd
108 changed files with 1939 additions and 1353 deletions

View File

@ -228,6 +228,8 @@ pref("general.autoScroll", true);
pref("browser.shell.checkDefaultBrowser", true);
pref("browser.shell.shortcutFavicons",true);
pref("browser.shell.mostRecentDateSetAsDefault", "");
pref("browser.shell.skipDefaultBrowserCheck", true);
pref("browser.shell.defaultBrowserCheckCount", 0);
// 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
// The behavior of option 3 is detailed at: http://wiki.mozilla.org/Session_Restore

View File

@ -24,11 +24,15 @@ LOCAL_INCLUDES += [
if CONFIG['OS_ARCH'] == 'WINNT':
OS_LIBS += [
'esent',
'ole32',
'shell32',
'shlwapi',
'version',
]
DELAYLOAD_DLLS += [
'esent.dll',
]
# Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
# GTK2: Need to link with glib for GNOME shell service

View File

@ -10,6 +10,12 @@
#define NS_IEHISTORYENUMERATOR_CONTRACTID \
"@mozilla.org/profile/migrator/iehistoryenumerator;1"
#define NS_EDGEREADINGLISTEXTRACTOR_CID \
{ 0xeeff77b1, 0xdb98, 0x4241, { 0x94, 0x36, 0x14, 0xf7, 0xa2, 0x28, 0x84, 0xc1 } }
#define NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID \
"@mozilla.org/profile/migrator/edgereadinglistextractor;1"
#endif
#define NS_SHELLSERVICE_CID \

View File

@ -18,6 +18,7 @@
#if defined(XP_WIN)
#include "nsIEHistoryEnumerator.h"
#include "nsEdgeReadingListExtractor.h"
#endif
#include "rdf.h"
@ -42,6 +43,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsGNOMEShellService, Init)
#if defined(XP_WIN)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsEdgeReadingListExtractor)
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
@ -56,6 +58,7 @@ NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
#if defined(XP_WIN)
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
NS_DEFINE_NAMED_CID(NS_EDGEREADINGLISTEXTRACTOR_CID);
#elif defined(XP_MACOSX)
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
#endif
@ -71,6 +74,7 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
#if defined(XP_WIN)
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
{ &kNS_EDGEREADINGLISTEXTRACTOR_CID, false, nullptr, nsEdgeReadingListExtractorConstructor },
#elif defined(XP_MACOSX)
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
#endif
@ -119,6 +123,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#if defined(XP_WIN)
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
{ NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID, &kNS_EDGEREADINGLISTEXTRACTOR_CID },
#elif defined(XP_MACOSX)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif

View File

@ -1,30 +1,30 @@
/* 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource:///modules/MSMigrationUtils.jsm");
function EdgeProfileMigrator() {
}
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
EdgeProfileMigrator.prototype.getResources = function() {
let resources = [
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
];
return resources.filter(r => r.exists);
};
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
/* 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource:///modules/MigrationUtils.jsm");
Cu.import("resource:///modules/MSMigrationUtils.jsm");
function EdgeProfileMigrator() {
}
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
EdgeProfileMigrator.prototype.getResources = function() {
let resources = [
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
MSMigrationUtils.getCookiesMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
];
return resources.filter(r => r.exists);
};
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);

View File

@ -84,7 +84,8 @@ History.prototype = {
let transitionType = this._typedURLs[uri.spec] ?
Ci.nsINavHistoryService.TRANSITION_TYPED :
Ci.nsINavHistoryService.TRANSITION_LINK;
let lastVisitTime = entry.get("time");
// use the current date if we have no visits for this entry
let lastVisitTime = entry.get("time") || Date.now();
places.push(
{ uri: uri,

File diff suppressed because it is too large Load Diff

View File

@ -10,12 +10,14 @@ JAR_MANIFESTS += ['jar.mn']
XPIDL_SOURCES += [
'nsIBrowserProfileMigrator.idl',
'nsIEdgeReadingListExtractor.idl',
]
XPIDL_MODULE = 'migration'
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'nsEdgeReadingListExtractor.cpp',
'nsIEHistoryEnumerator.cpp',
]

View File

@ -0,0 +1,203 @@
/* 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/. */
#include "nsEdgeReadingListExtractor.h"
#include <windows.h>
#include "nsCOMPtr.h"
#include "nsIConsoleService.h"
#include "nsIMutableArray.h"
#include "nsIWritablePropertyBag2.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsWindowsMigrationUtils.h"
#define NS_HANDLE_JET_ERROR(err) { \
if (err < JET_errSuccess) { \
rv = ConvertJETError(err); \
goto CloseDB; \
} \
}
#define MAX_URL_LENGTH 4168
#define MAX_TITLE_LENGTH 1024
NS_IMPL_ISUPPORTS(nsEdgeReadingListExtractor, nsIEdgeReadingListExtractor)
NS_IMETHODIMP
nsEdgeReadingListExtractor::Extract(const nsAString& aDBPath, nsIArray** aItems)
{
nsresult rv = NS_OK;
*aItems = nullptr;
JET_ERR err;
JET_INSTANCE instance;
JET_SESID sesid;
JET_DBID dbid;
JET_TABLEID tableid;
JET_COLUMNDEF urlColumnInfo = { 0 };
JET_COLUMNDEF titleColumnInfo = { 0 };
JET_COLUMNDEF addedDateColumnInfo = { 0 };
// Need to ensure this happens before we skip ahead to CloseDB,
// otherwise the compiler complains.
nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
// JET does not throw exceptions, and so error handling and ensuring we close
// the DB is a bit finnicky. Keep track of how far we got so we guarantee closing
// the right things
bool instanceCreated, sessionCreated, dbOpened, tableOpened;
char16_t* dbPath = ToNewUnicode(aDBPath);
// Check for the right page size and initialize with that
unsigned long pageSize;
err = JetGetDatabaseFileInfoW(dbPath, &pageSize, sizeof(pageSize), JET_DbInfoPageSize);
NS_HANDLE_JET_ERROR(err)
err = JetSetSystemParameter(&instance, NULL, JET_paramDatabasePageSize, pageSize, NULL);
NS_HANDLE_JET_ERROR(err)
// Turn off recovery, because otherwise we will create log files in either the cwd or
// overwrite Edge's own logfiles, which is useless at best and at worst might mess with
// Edge actually using the DB
err = JetSetSystemParameter(&instance, NULL, JET_paramRecovery, NULL, "Off");
NS_HANDLE_JET_ERROR(err)
// Start our session:
err = JetCreateInstance(&instance, "edge_readinglist_migration");
NS_HANDLE_JET_ERROR(err)
instanceCreated = true;
err = JetInit(&instance);
NS_HANDLE_JET_ERROR(err)
err = JetBeginSession(instance, &sesid, 0, 0);
NS_HANDLE_JET_ERROR(err)
sessionCreated = true;
// Actually open the DB, and make sure to do so readonly:
err = JetAttachDatabaseW(sesid, dbPath, JET_bitDbReadOnly);
NS_HANDLE_JET_ERROR(err)
dbOpened = true;
err = JetOpenDatabaseW(sesid, dbPath, NULL, &dbid, JET_bitDbReadOnly);
NS_HANDLE_JET_ERROR(err)
// Open the readinglist table and get information on the columns we are interested in:
err = JetOpenTable(sesid, dbid, "ReadingList", NULL, 0, JET_bitTableReadOnly, &tableid);
NS_HANDLE_JET_ERROR(err)
tableOpened = true;
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "URL", &urlColumnInfo,
sizeof(urlColumnInfo), JET_ColInfo);
NS_HANDLE_JET_ERROR(err)
if (urlColumnInfo.cbMax > MAX_URL_LENGTH) {
nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (consoleService) {
consoleService->LogStringMessage(NS_LITERAL_STRING("Edge migration: URL column size increased").get());
}
}
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "Title", &titleColumnInfo,
sizeof(titleColumnInfo), JET_ColInfo);
NS_HANDLE_JET_ERROR(err)
if (titleColumnInfo.cbMax > MAX_TITLE_LENGTH) {
nsCOMPtr<nsIConsoleService> consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (consoleService) {
consoleService->LogStringMessage(NS_LITERAL_STRING("Edge migration: Title column size increased").get());
}
}
err = JetGetColumnInfo(sesid, dbid, "ReadingList", "AddedDate", &addedDateColumnInfo,
sizeof(addedDateColumnInfo), JET_ColInfo);
NS_HANDLE_JET_ERROR(err)
// verify the column types are what we expect:
if (urlColumnInfo.coltyp != JET_coltypLongText ||
titleColumnInfo.coltyp != JET_coltypLongText ||
addedDateColumnInfo.coltyp != JET_coltypLongLong) {
rv = NS_ERROR_NOT_IMPLEMENTED;
goto CloseDB;
}
JET_COLUMNID urlColumnId = urlColumnInfo.columnid;
JET_COLUMNID titleColumnId = titleColumnInfo.columnid;
JET_COLUMNID addedDateColumnId = addedDateColumnInfo.columnid;
// If we got here, we've found our table and column information
err = JetMove(sesid, tableid, JET_MoveFirst, 0);
// It's possible there are 0 items in this table, in which case we want to
// not fail:
if (err == JET_errNoCurrentRecord) {
items.forget(aItems);
goto CloseDB;
}
// Check for any other errors
NS_HANDLE_JET_ERROR(err)
FILETIME addedDate;
wchar_t urlBuffer[MAX_URL_LENGTH] = { 0 };
wchar_t titleBuffer[MAX_TITLE_LENGTH] = { 0 };
do {
err = JetRetrieveColumn(sesid, tableid, urlColumnId, &urlBuffer,
sizeof(urlBuffer), NULL, 0, NULL);
NS_HANDLE_JET_ERROR(err)
err = JetRetrieveColumn(sesid, tableid, titleColumnId, &titleBuffer,
sizeof(titleBuffer), NULL, 0, NULL);
NS_HANDLE_JET_ERROR(err)
err = JetRetrieveColumn(sesid, tableid, addedDateColumnId, &addedDate,
sizeof(addedDate), NULL, 0, NULL);
NS_HANDLE_JET_ERROR(err)
nsCOMPtr<nsIWritablePropertyBag2> pbag = do_CreateInstance("@mozilla.org/hash-property-bag;1");
bool dateIsValid;
PRTime prAddedDate = WinMigrationFileTimeToPRTime(&addedDate, &dateIsValid);
nsDependentString url(urlBuffer);
nsDependentString title(titleBuffer);
pbag->SetPropertyAsAString(NS_LITERAL_STRING("uri"), url);
pbag->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
if (dateIsValid) {
pbag->SetPropertyAsInt64(NS_LITERAL_STRING("time"), prAddedDate);
}
items->AppendElement(pbag, false);
memset(urlBuffer, 0, sizeof(urlBuffer));
memset(titleBuffer, 0, sizeof(titleBuffer));
} while (JET_errSuccess == JetMove(sesid, tableid, JET_MoveNext, 0));
items.forget(aItems);
CloseDB:
// Terminate ESENT. This performs a clean shutdown.
// Ignore errors while closing:
if (tableOpened)
JetCloseTable(sesid, tableid);
if (dbOpened)
JetCloseDatabase(sesid, dbid, 0);
if (sessionCreated)
JetEndSession(sesid, 0);
if (instanceCreated)
JetTerm(instance);
return rv;
}
nsresult
nsEdgeReadingListExtractor::ConvertJETError(const JET_ERR &aError)
{
switch (aError) {
case JET_errPageSizeMismatch:
case JET_errInvalidName:
case JET_errColumnNotFound:
// The DB format has changed and we haven't updated this migration code:
return NS_ERROR_NOT_IMPLEMENTED;
case JET_errDatabaseLocked:
return NS_ERROR_FILE_IS_LOCKED;
case JET_errPermissionDenied:
case JET_errAccessDenied:
return NS_ERROR_FILE_ACCESS_DENIED;
case JET_errInvalidFilename:
return NS_ERROR_FILE_INVALID_PATH;
case JET_errFileNotFound:
return NS_ERROR_FILE_NOT_FOUND;
default:
return NS_ERROR_FAILURE;
}
}

View File

@ -0,0 +1,31 @@
/* 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/. */
#ifndef edgereadinglistextractor__h__
#define edgereadinglistextractor__h__
#include "nsIArray.h"
#include "nsIEdgeReadingListExtractor.h"
// To get access to the long data types, we need to use at least the Vista version of the JET APIs
#undef JET_VERSION
#define JET_VERSION 0x0600
#include <esent.h>
class nsEdgeReadingListExtractor final : public nsIEdgeReadingListExtractor
{
public:
nsEdgeReadingListExtractor() {}
NS_DECL_ISUPPORTS
NS_DECL_NSIEDGEREADINGLISTEXTRACTOR
private:
~nsEdgeReadingListExtractor() {}
nsresult ConvertJETError(const JET_ERR &err);
};
#endif

View File

@ -7,37 +7,13 @@
#include <urlhist.h>
#include <shlguid.h>
#include "nsStringAPI.h"
#include "nsNetUtil.h"
#include "prtime.h"
#include "nsIVariant.h"
#include "nsCOMArray.h"
#include "nsArrayEnumerator.h"
namespace {
PRTime FileTimeToPRTime(FILETIME* filetime)
{
SYSTEMTIME st;
::FileTimeToSystemTime(filetime, &st);
PRExplodedTime prt;
prt.tm_year = st.wYear;
// SYSTEMTIME's day-of-month parameter is 1-based,
// PRExplodedTime's is 0-based.
prt.tm_month = st.wMonth - 1;
prt.tm_mday = st.wDay;
prt.tm_hour = st.wHour;
prt.tm_min = st.wMinute;
prt.tm_sec = st.wSecond;
prt.tm_usec = st.wMilliseconds * 1000;
prt.tm_wday = 0;
prt.tm_yday = 0;
prt.tm_params.tp_gmt_offset = 0;
prt.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&prt);
}
} // namespace
#include "nsCOMArray.h"
#include "nsIVariant.h"
#include "nsNetUtil.h"
#include "nsStringAPI.h"
#include "nsWindowsMigrationUtils.h"
#include "prtime.h"
////////////////////////////////////////////////////////////////////////////////
//// nsIEHistoryEnumerator
@ -106,14 +82,17 @@ nsIEHistoryEnumerator::HasMoreElements(bool* _retval)
nsDependentString title(statURL.pwcsTitle);
PRTime lastVisited = FileTimeToPRTime(&(statURL.ftLastVisited));
bool lastVisitTimeIsValid;
PRTime lastVisited = WinMigrationFileTimeToPRTime(&(statURL.ftLastVisited), &lastVisitTimeIsValid);
mCachedNextEntry = do_CreateInstance("@mozilla.org/hash-property-bag;1");
MOZ_ASSERT(mCachedNextEntry, "Should have instanced a new property bag");
if (mCachedNextEntry) {
mCachedNextEntry->SetPropertyAsInterface(NS_LITERAL_STRING("uri"), uri);
mCachedNextEntry->SetPropertyAsAString(NS_LITERAL_STRING("title"), title);
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
if (lastVisitTimeIsValid) {
mCachedNextEntry->SetPropertyAsInt64(NS_LITERAL_STRING("time"), lastVisited);
}
*_retval = true;
}

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#include "nsISupports.idl"
interface nsIArray;
[scriptable, uuid(bfdef4aa-dcd1-4d31-b5d9-188fe8d98623)]
interface nsIEdgeReadingListExtractor : nsISupports
{
/**
* Import data from the database indicated by the databasePath
* May fail if the path is invalid, unreadable, the database is corrupt,
* or the data in the database is not in the format we expect.
*
* @param databasePath the absolute path to the database we'd like to import
* @return an enumerator of nsIPropertyBag2 items that each have a URL, title, and
* creation dates.
*/
nsIArray extract(in DOMString databasePath);
};

View File

@ -0,0 +1,36 @@
/* 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/. */
#ifndef windowsmigrationutils__h__
#define windowsmigrationutils__h__
#include "prtime.h"
static
PRTime WinMigrationFileTimeToPRTime(FILETIME* filetime, bool* isValid)
{
SYSTEMTIME st;
*isValid = ::FileTimeToSystemTime(filetime, &st);
if (!*isValid) {
return 0;
}
PRExplodedTime prt;
prt.tm_year = st.wYear;
// SYSTEMTIME's day-of-month parameter is 1-based,
// PRExplodedTime's is 0-based.
prt.tm_month = st.wMonth - 1;
prt.tm_mday = st.wDay;
prt.tm_hour = st.wHour;
prt.tm_min = st.wMinute;
prt.tm_sec = st.wSecond;
prt.tm_usec = st.wMilliseconds * 1000;
prt.tm_wday = 0;
prt.tm_yday = 0;
prt.tm_params.tp_gmt_offset = 0;
prt.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&prt);
}
#endif

View File

@ -317,11 +317,55 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes,
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs) {
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
// Reset the number of times the dialog should be shown
// before it is silenced.
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
}
return NS_OK;
}
NS_IMETHODIMP
nsGNOMEShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
if (NS_FAILED(rv)) {
return rv;
}
if (*aResult) {
// Only skip the default browser check once. The next attempt in
// a new session should proceed.
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
}
int32_t defaultBrowserCheckCount;
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
&defaultBrowserCheckCount);
if (NS_FAILED(rv)) {
return rv;
}
if (defaultBrowserCheckCount < 3) {
*aResult = false;
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
defaultBrowserCheckCount + 1);
}
// Disable the default browser check after three attempts.
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
// user-initiated action and it shouldn't get re-enabled
// if it has been user disabled.
*aResult = true;
return rv;
}
NS_IMETHODIMP
nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
@ -333,6 +377,18 @@ nsGNOMEShellService::GetShouldCheckDefaultBrowser(bool* aResult)
}
nsresult rv;
#ifndef RELEASE_BUILD
bool skipDefaultBrowserCheck;
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
if (NS_FAILED(rv)) {
return rv;
}
if (skipDefaultBrowserCheck) {
*aResult = false;
return rv;
}
#endif
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;

View File

@ -8,7 +8,7 @@
interface nsIDOMElement;
interface nsIFile;
[scriptable, uuid(99d2e9f1-3c86-40f7-81fd-3060c18489f0)]
[scriptable, uuid(55cb78a8-2fc4-48f4-9345-ff0e541c5cc4)]
interface nsIShellService : nsISupports
{
/**
@ -38,7 +38,7 @@ interface nsIShellService : nsISupports
*/
void setDefaultBrowser(in boolean aClaimAllTypes, in boolean aForAllUsers);
/**
/**
* Used to determine whether or not to show a "Set Default Browser"
* query dialog. This attribute is true if the application is starting
* up and "browser.shell.checkDefaultBrowser" is true, otherwise it
@ -46,6 +46,13 @@ interface nsIShellService : nsISupports
*/
attribute boolean shouldCheckDefaultBrowser;
/**
* Used to determine whether or not the "Set Default Browser" check
* should be skipped during first-run or after the browser has been
* run a few times.
*/
readonly attribute boolean shouldSkipCheckDefaultBrowser;
/**
* Used to determine whether or not to offer "Set as desktop background"
* functionality. Even if shell service is available it is not

View File

@ -95,11 +95,55 @@ nsMacShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs) {
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
// Reset the number of times the dialog should be shown
// before it is silenced.
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
}
return NS_OK;
}
NS_IMETHODIMP
nsMacShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
if (NS_FAILED(rv)) {
return rv;
}
if (*aResult) {
// Only skip the default browser check once. The next attempt in
// a new session should proceed.
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
}
int32_t defaultBrowserCheckCount;
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
&defaultBrowserCheckCount);
if (NS_FAILED(rv)) {
return rv;
}
if (defaultBrowserCheckCount < 3) {
*aResult = false;
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
defaultBrowserCheckCount + 1);
}
// Disable the default browser check after three attempts.
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
// user-initiated action and it shouldn't get re-enabled
// if it has been user disabled.
*aResult = true;
return rv;
}
NS_IMETHODIMP
nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
@ -111,6 +155,18 @@ nsMacShellService::GetShouldCheckDefaultBrowser(bool* aResult)
}
nsresult rv;
#ifndef RELEASE_BUILD
bool skipDefaultBrowserCheck;
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
if (NS_FAILED(rv)) {
return rv;
}
if (skipDefaultBrowserCheck) {
*aResult = false;
return rv;
}
#endif
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;

View File

@ -4,6 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#define PREF_CHECKDEFAULTBROWSER "browser.shell.checkDefaultBrowser"
#define PREF_SKIPDEFAULTBROWSERCHECK "browser.shell.skipDefaultBrowserCheck"
#define PREF_DEFAULTBROWSERCHECKCOUNT "browser.shell.defaultBrowserCheckCount"
#define SHELLSERVICE_PROPERTIES "chrome://browser/locale/shellservice.properties"
#define BRAND_PROPERTIES "chrome://branding/locale/brand.properties"

View File

@ -976,17 +976,61 @@ nsWindowsShellService::SetDefaultBrowser(bool aClaimAllTypes, bool aForAllUsers)
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefs) {
(void) prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
// Reset the number of times the dialog should be shown
// before it is silenced.
(void) prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
}
return rv;
}
NS_IMETHODIMP
nsWindowsShellService::GetShouldSkipCheckDefaultBrowser(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;
}
rv = prefs->GetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, aResult);
if (NS_FAILED(rv)) {
return rv;
}
if (*aResult) {
// Only skip the default browser check once. The next attempt in
// a new session should proceed.
return prefs->SetBoolPref(PREF_SKIPDEFAULTBROWSERCHECK, false);
}
int32_t defaultBrowserCheckCount;
rv = prefs->GetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
&defaultBrowserCheckCount);
if (NS_FAILED(rv)) {
return rv;
}
if (defaultBrowserCheckCount < 3) {
*aResult = false;
return prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT,
defaultBrowserCheckCount + 1);
}
// Disable the default browser check after three attempts.
// Don't modify PREF_CHECKDEFAULTBROWSER since that is a
// user-initiated action and it shouldn't get re-enabled
// if it has been user disabled.
*aResult = true;
return rv;
}
NS_IMETHODIMP
nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
// If we've already checked, the browser has been started and this is a
// If we've already checked, the browser has been started and this is a
// new window open, and we don't want to check again.
if (mCheckedThisSession) {
*aResult = false;
@ -994,6 +1038,18 @@ nsWindowsShellService::GetShouldCheckDefaultBrowser(bool* aResult)
}
nsresult rv;
#ifndef RELEASE_BUILD
bool skipDefaultBrowserCheck;
rv = GetShouldSkipCheckDefaultBrowser(&skipDefaultBrowserCheck);
if (NS_FAILED(rv)) {
return rv;
}
if (skipDefaultBrowserCheck) {
*aResult = false;
return rv;
}
#endif
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
if (NS_FAILED(rv)) {
return rv;

View File

@ -108,9 +108,7 @@ browser.jar:
content/browser/devtools/performance/views/details-js-flamegraph.js (performance/views/details-js-flamegraph.js)
content/browser/devtools/performance/views/details-memory-call-tree.js (performance/views/details-memory-call-tree.js)
content/browser/devtools/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
content/browser/devtools/performance/views/details-optimizations.js (performance/views/details-optimizations.js)
content/browser/devtools/performance/views/optimizations-list.js (performance/views/optimizations-list.js)
content/browser/devtools/performance/views/frames-list.js (performance/views/frames-list.js)
content/browser/devtools/performance/views/recordings.js (performance/views/recordings.js)
content/browser/devtools/promisedebugger/promise-debugger.js (promisedebugger/promise-debugger.js)
content/browser/devtools/promisedebugger/promise-debugger.xhtml (promisedebugger/promise-debugger.xhtml)

View File

@ -354,13 +354,16 @@ const Formatters = {
return marker.name || L10N.getStr("marker.label.unknown");
},
GCLabel: function (marker={}) {
GCLabel: function (marker) {
if (!marker) {
return L10N.getStr("marker.label.garbageCollection2");
}
// Only if a `nonincrementalReason` exists, do we want to label
// this as a non incremental GC event.
if ("nonincrementalReason" in marker) {
return L10N.getStr("marker.label.garbageCollection.nonIncremental");
}
return L10N.getStr("marker.label.garbageCollection");
return L10N.getStr("marker.label.garbageCollection.incremental");
},
JSLabel: function (marker={}) {

View File

@ -13,36 +13,75 @@ const { L10N } = require("devtools/performance/global");
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
const MILLISECOND_UNITS = L10N.getStr("table.ms");
const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext");
const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext2");
const CALL_TREE_INDENTATION = 16; // px
// Used for rendering values in cells
const FORMATTERS = {
TIME: (value) => L10N.getFormatStr("table.ms2", L10N.numberWithDecimals(value, 2)),
PERCENT: (value) => L10N.getFormatStr("table.percentage2", L10N.numberWithDecimals(value, 2)),
NUMBER: (value) => value || 0,
BYTESIZE: (value) => L10N.getFormatStr("table.bytes", (value || 0))
};
/**
* Definitions for rendering cells. Triads of class name, property name from
* `frame.getInfo()`, and a formatter function.
*/
const CELLS = {
duration: ["duration", "totalDuration", FORMATTERS.TIME],
percentage: ["percentage", "totalPercentage", FORMATTERS.PERCENT],
selfDuration: ["self-duration", "selfDuration", FORMATTERS.TIME],
selfPercentage: ["self-percentage", "selfPercentage", FORMATTERS.PERCENT],
samples: ["samples", "samples", FORMATTERS.NUMBER],
selfSize: ["self-size", "selfSize", FORMATTERS.BYTESIZE],
selfSizePercentage: ["self-size-percentage", "selfSizePercentage", FORMATTERS.PERCENT],
selfCount: ["self-count", "selfCount", FORMATTERS.NUMBER],
selfCountPercentage: ["self-count-percentage", "selfCountPercentage", FORMATTERS.PERCENT],
size: ["size", "totalSize", FORMATTERS.BYTESIZE],
sizePercentage: ["size-percentage", "totalSizePercentage", FORMATTERS.PERCENT],
count: ["count", "totalCount", FORMATTERS.NUMBER],
countPercentage: ["count-percentage", "totalCountPercentage", FORMATTERS.PERCENT],
};
const CELL_TYPES = Object.keys(CELLS);
const DEFAULT_SORTING_PREDICATE = (frameA, frameB) => {
let dataA = frameA.getDisplayedData();
let dataB = frameB.getDisplayedData();
if (this.inverted) {
// Invert trees, sort by selfPercentage, and then totalPercentage
if (dataA.selfPercentage === dataB.selfPercentage) {
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
}
return dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1;
let isAllocations = "totalSize" in dataA;
if (isAllocations) {
return this.inverted && dataA.selfSize !== dataB.selfSize ?
(dataA.selfSize < dataB.selfSize ? 1 : - 1) :
(dataA.totalSize < dataB.totalSize ? 1 : -1);
}
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
return this.inverted && dataA.selfPercentage !== dataB.selfPercentage ?
(dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1) :
(dataA.totalPercentage < dataB.totalPercentage ? 1 : -1);
};
const DEFAULT_AUTO_EXPAND_DEPTH = 3; // depth
const DEFAULT_VISIBLE_CELLS = {
duration: true,
percentage: true,
count: false,
selfDuration: true,
selfPercentage: true,
selfCount: false,
samples: true,
function: true
function: true,
// allocation columns
count: false,
selfCount: false,
size: false,
selfSize: false,
countPercentage: false,
selfCountPercentage: false,
sizePercentage: false,
selfSizePercentage: false,
};
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
@ -136,27 +175,14 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
let frameInfo = this.getDisplayedData();
let cells = [];
if (this.visibleCells.duration) {
cells.push(this._createTimeCell(document, frameInfo.totalDuration));
}
if (this.visibleCells.percentage) {
cells.push(this._createExecutionCell(document, frameInfo.totalPercentage));
}
if (this.visibleCells.count) {
cells.push(this._createCountCell(document, frameInfo.totalCount));
}
if (this.visibleCells.selfDuration) {
cells.push(this._createTimeCell(document, frameInfo.selfDuration, true));
}
if (this.visibleCells.selfPercentage) {
cells.push(this._createExecutionCell(document, frameInfo.selfPercentage, true));
}
if (this.visibleCells.selfCount) {
cells.push(this._createCountCell(document, frameInfo.selfCount, true));
}
if (this.visibleCells.samples) {
cells.push(this._createSamplesCell(document, frameInfo.samples));
for (let type of CELL_TYPES) {
if (this.visibleCells[type]) {
// Inline for speed, but pass in the formatted value via
// cell definition, as well as the element type.
cells.push(this._createCell(document, CELLS[type][2](frameInfo[CELLS[type][1]]), CELLS[type][0]));
}
}
if (this.visibleCells.function) {
cells.push(this._createFunctionCell(document, arrowNode, frameInfo.name, frameInfo, this.level));
}
@ -204,38 +230,15 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
* Functions creating each cell in this call view.
* Invoked by `_displaySelf`.
*/
_createTimeCell: function(doc, duration, isSelf = false) {
_createCell: function (doc, value, type) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-duration" : "duration");
cell.setAttribute("type", type);
cell.setAttribute("crop", "end");
cell.setAttribute("value", L10N.numberWithDecimals(duration, 2) + " " + MILLISECOND_UNITS);
return cell;
},
_createExecutionCell: function(doc, percentage, isSelf = false) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
cell.setAttribute("crop", "end");
cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS);
return cell;
},
_createCountCell: function(doc, count, isSelf = false) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-count" : "count");
cell.setAttribute("crop", "end");
cell.setAttribute("value", count || 0);
return cell;
},
_createSamplesCell: function(doc, count) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", "samples");
cell.setAttribute("crop", "end");
cell.setAttribute("value", count || 0);
cell.setAttribute("value", value);
return cell;
},
_createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
let cell = doc.createElement("hbox");
cell.className = "call-tree-cell";
@ -243,12 +246,10 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
cell.setAttribute("type", "function");
cell.appendChild(arrowNode);
// Render optimization link to JIT view if the frame
// has optimizations
// Render optimization hint if this frame has opt data.
if (this.root.showOptimizationHint && frameInfo.hasOptimizations && !frameInfo.isMetaCategory) {
let icon = doc.createElement("description");
icon.setAttribute("tooltiptext", VIEW_OPTIMIZATIONS_TOOLTIP);
icon.setAttribute("type", "linkable");
icon.className = "opt-icon";
cell.appendChild(icon);
}

View File

@ -116,7 +116,7 @@ const EVENTS = {
// When the PerformanceView updates the display of the buffer status
UI_BUFFER_STATUS_UPDATED: "Performance:UI:BufferUpdated",
// Emitted by the JITOptimizationsView when it renders new optimization
// Emitted by the OptimizationsListView when it renders new optimization
// data and clears the optimization data
OPTIMIZATIONS_RESET: "Performance:UI:OptimizationsReset",
OPTIMIZATIONS_RENDERED: "Performance:UI:OptimizationsRendered",

View File

@ -24,11 +24,9 @@
<script type="application/javascript" src="performance/views/details-js-flamegraph.js"/>
<script type="application/javascript" src="performance/views/details-memory-call-tree.js"/>
<script type="application/javascript" src="performance/views/details-memory-flamegraph.js"/>
<script type="application/javascript" src="performance/views/details-optimizations.js"/>
<script type="application/javascript" src="performance/views/details.js"/>
<script type="application/javascript" src="performance/views/recordings.js"/>
<script type="application/javascript" src="performance/views/optimizations-list.js"/>
<script type="application/javascript" src="performance/views/frames-list.js"/>
<popupset id="performance-options-popupset">
<menupopup id="performance-filter-menupopup"/>
@ -144,11 +142,6 @@
label="&performanceUI.toolbar.memory-flamegraph;"
hidden="true"
data-view="memory-flamegraph" />
<toolbarbutton id="select-optimizations-view"
class="devtools-toolbarbutton devtools-button"
label="Optimizations"
hidden="true"
data-view="optimizations" />
</hbox>
<spacer flex="1"></spacer>
<hbox id="performance-toolbar-controls-options"
@ -298,6 +291,20 @@
</hbox>
<vbox class="call-tree-cells-container" flex="1"/>
</vbox>
<splitter class="devtools-side-splitter"/>
<!-- Optimizations Panel -->
<vbox id="jit-optimizations-view"
class="hidden">
<toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
<hbox id="jit-optimizations-header">
<span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
<span class="header-function-name" />
<span class="header-file opt-url debugger-link" />
<span class="header-line opt-line" />
</hbox>
</toolbar>
<vbox id="jit-optimizations-raw-view"></vbox>
</vbox>
</hbox>
<!-- JS FlameChart -->
@ -308,15 +315,45 @@
<vbox id="memory-calltree-view" flex="1">
<hbox class="call-tree-headers-container">
<label class="plain call-tree-header"
type="count"
type="self-size"
crop="end"
value="&performanceUI.table.totalAlloc;"
value="Self Bytes"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-size-percentage"
crop="end"
value="Self Bytes %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-count"
crop="end"
value="&performanceUI.table.selfAlloc;"
tooltiptext="&performanceUI.table.selfAlloc.tooltip;"/>
value="Self Count"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-count-percentage"
crop="end"
value="Self Count %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="size"
crop="end"
value="Total Size"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="size-percentage"
crop="end"
value="Total Size %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="count"
crop="end"
value="Total Count"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="count-percentage"
crop="end"
value="Total Count %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="function"
crop="end"
@ -328,47 +365,6 @@
<!-- Memory FlameChart -->
<hbox id="memory-flamegraph-view" flex="1">
</hbox>
<!-- JIT View -->
<hbox id="optimizations-view" flex="1">
<hbox id="graph-placeholder" flex="1">
</hbox>
<splitter id="optimizations-splitter" class="devtools-side-splitter"/>
<tabbox id="optimizations-tabs"
class="devtools-sidebar-tabs"
handleCtrlTab="false">
<tabs>
<tab id="optimizations-optimizations-tab"
label="Optimizations" />
<tab id="optimizations-frames-tab"
label="Frames" />
</tabs>
<tabpanels flex="1">
<!-- Optimizations Panel -->
<tabpanel id="optimizations-tabpanel"
class="tabpanel-content">
<vbox id="jit-optimizations-view">
<toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
<hbox id="jit-optimizations-header">
<span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
<span class="header-function-name" />
<span class="header-file opt-url debugger-link" />
<span class="header-line opt-line" />
</hbox>
</toolbar>
<vbox id="jit-optimizations-raw-view"></vbox>
</vbox>
</tabpanel>
<!-- Frames Panel -->
<tabpanel id="frames-tabpanel"
class="tabpanel-content">
</tabpanel>
</tabpanels>
</tabbox>
</hbox>
<!-- /JIT View -->
</deck>
</deck>
</vbox>

View File

@ -42,8 +42,8 @@ skip-if = true # Bug 1161817
[browser_perf-details-07.js]
[browser_perf-events-calltree.js]
[browser_perf-highlighted.js]
#[browser_perf-jit-view-01.js] bug 1176056
#[browser_perf-jit-view-02.js] bug 1176056
[browser_perf-jit-view-01.js]
[browser_perf-jit-view-02.js]
[browser_perf-legacy-front-01.js]
[browser_perf-legacy-front-02.js]
[browser_perf-legacy-front-03.js]
@ -69,7 +69,6 @@ skip-if = os == 'linux' # Bug 1172120
[browser_perf-options-show-idle-blocks-02.js]
[browser_perf-options-enable-memory-01.js]
[browser_perf-options-enable-memory-02.js]
[browser_perf-options-enable-optimizations.js]
[browser_perf-options-enable-framerate.js]
[browser_perf-options-allocations.js]
[browser_perf-options-profiler.js]

View File

@ -24,9 +24,15 @@ function* spawnTest() {
"duration": false,
"percentage": false,
"count": true,
"count-percentage": true,
"size": true,
"size-percentage": true,
"self-duration": false,
"self-percentage": false,
"self-count": true,
"self-count-percentage": true,
"self-size": true,
"self-size-percentage": true,
"samples": false,
"function": true
});

View File

@ -11,7 +11,7 @@ Services.prefs.setBoolPref(INVERT_PREF, false);
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView, RecordingsView } = panel.panelWin;
let profilerData = { threads: [gThread] }
@ -42,7 +42,7 @@ function* spawnTest() {
yield checkFrame(3);
let select = once(PerformanceController, EVENTS.RECORDING_SELECTED);
let reset = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RESET);
let reset = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RESET);
RecordingsView.selectedIndex = 0;
yield Promise.all([select, reset]);
ok(true, "JITOptimizations view correctly reset when switching recordings.");
@ -67,11 +67,12 @@ function* spawnTest() {
}
function *checkFrame (frameIndex, expectedOpts=[]) {
info(`Checking frame ${frameIndex}`);
// Click the frame
let rendered = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
let rendered = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RENDERED);
mousedown(window, $$(".call-tree-item")[frameIndex]);
yield rendered;
ok(true, "JITOptimizationsView rendered when enabling with the current frame node selected");
ok(true, "OptimizationsListView rendered when enabling with the current frame node selected");
let isEmpty = $("#jit-optimizations-view").classList.contains("empty");
if (expectedOpts.length === 0) {
@ -85,7 +86,7 @@ function* spawnTest() {
// share the same frame info
let frameInfo = expectedOpts[0].opt._testFrameInfo;
let { $headerName, $headerLine, $headerFile } = JITOptimizationsView;
let { $headerName, $headerLine, $headerFile } = OptimizationsListView;
ok(!$headerName.hidden, "header function name should be shown");
ok(!$headerLine.hidden, "header line should be shown");
ok(!$headerFile.hidden, "header file should be shown");

View File

@ -2,17 +2,18 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the JIT Optimizations view does not display information
* Tests that the OptimizationsListView does not display information
* for meta nodes when viewing "content only".
*/
Services.prefs.setBoolPref(INVERT_PREF, false);
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
let { CATEGORY_MASK } = require("devtools/performance/global");
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
let { OverviewView, DetailsView, OptimizationsListView, JsCallTreeView, RecordingsView } = panel.panelWin;
let profilerData = { threads: [gThread] };
@ -31,14 +32,14 @@ function* spawnTest() {
yield injectAndRenderProfilerData();
// Click the frame
let rendered = once(JITOptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
let rendered = once(OptimizationsListView, EVENTS.OPTIMIZATIONS_RENDERED);
mousedown(window, $$(".call-tree-item")[2]);
yield rendered;
ok($("#jit-optimizations-view").classList.contains("empty"),
"platform meta frame shows as empty");
let { $headerName, $headerLine, $headerFile } = JITOptimizationsView;
let { $headerName, $headerLine, $headerFile } = OptimizationsListView;
ok(!$headerName.hidden, "header function name should be shown");
ok($headerLine.hidden, "header line should be hidden");
ok($headerFile.hidden, "header file should be hidden");

View File

@ -1,45 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that `enable-jit-optimizations` sets the recording to subsequently
* enable the Optimizations View.
*/
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $, DetailsView, WaterfallView, OptimizationsView } = panel.panelWin;
Services.prefs.setBoolPref(JIT_PREF, true);
yield startRecording(panel);
let rendered = once(OptimizationsView, EVENTS.OPTIMIZATIONS_RENDERED);
yield stopRecording(panel);
yield DetailsView.selectView("optimizations");
ok(DetailsView.isViewSelected(OptimizationsView), "The Optimizations View is now selected.");
yield rendered;
let recording = PerformanceController.getCurrentRecording();
is(recording.getConfiguration().withJITOptimizations, true, "recording model has withJITOptimizations as true");
// Set back to false, should not affect display of first recording
info("Disabling enable-jit-optimizations");
Services.prefs.setBoolPref(JIT_PREF, false);
is($("#select-optimizations-view").hidden, false,
"JIT Optimizations selector still available since the recording has it enabled.");
yield startRecording(panel);
rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
yield stopRecording(panel);
ok(DetailsView.isViewSelected(WaterfallView), "The waterfall view is now selected.");
yield rendered;
recording = PerformanceController.getCurrentRecording();
is(recording.getConfiguration().withJITOptimizations, false, "recording model has withJITOptimizations as false");
is($("#select-optimizations-view").hidden, true,
"JIT Optimizations selector is hidden if recording did not enable optimizations.");
yield teardown(panel);
finish();
}

View File

@ -19,6 +19,8 @@ add_task(function () {
"getMarkerLabel() returns a simple label");
equal(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
"getMarkerLabel() returns a label defined via function");
equal(Utils.getMarkerLabel({ name: "GarbageCollection", causeName: "ALLOC_TRIGGER" }), "Incremental GC",
"getMarkerLabel() returns a label for a function that is generalizable");
ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
"getMarkerFields() returns an empty array when no fields defined");
@ -53,7 +55,7 @@ add_task(function () {
equal(Utils.getMarkerClassName("Javascript"), "Function Call",
"getMarkerClassName() returns correct string when defined via function");
equal(Utils.getMarkerClassName("GarbageCollection"), "Incremental GC",
equal(Utils.getMarkerClassName("GarbageCollection"), "Garbage Collection",
"getMarkerClassName() returns correct string when defined via function");
equal(Utils.getMarkerClassName("Reflow"), "Layout",
"getMarkerClassName() returns correct string when defined via string");

View File

@ -23,14 +23,18 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
DetailsSubview.initialize.call(this);
this._onLink = this._onLink.bind(this);
this._onFocus = this._onFocus.bind(this);
this.container = $("#js-calltree-view .call-tree-cells-container");
OptimizationsListView.initialize();
},
/**
* Unbinds events.
*/
destroy: function () {
OptimizationsListView.destroy();
this.container = null;
DetailsSubview.destroy.call(this);
},
@ -44,17 +48,44 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
render: function (interval={}) {
let recording = PerformanceController.getCurrentRecording();
let profile = recording.getProfile();
let optimizations = recording.getConfiguration().withJITOptimizations;
let options = {
contentOnly: !PerformanceController.getOption("show-platform-data"),
invertTree: PerformanceController.getOption("invert-call-tree"),
flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
showOptimizationHint: recording.getConfiguration().withJITOptimizations,
showOptimizationHint: optimizations
};
let threadNode = this._prepareCallTree(profile, interval, options);
this._populateCallTree(threadNode, options);
if (optimizations) {
this.showOptimizations();
} else {
this.hideOptimizations();
}
OptimizationsListView.reset();
this.emit(EVENTS.JS_CALL_TREE_RENDERED);
},
showOptimizations: function () {
$("#jit-optimizations-view").classList.remove("hidden");
},
hideOptimizations: function () {
$("#jit-optimizations-view").classList.add("hidden");
},
_onFocus: function (_, treeItem) {
if (PerformanceController.getCurrentRecording().getConfiguration().withJITOptimizations) {
OptimizationsListView.setCurrentFrame(treeItem.frame);
OptimizationsListView.render();
}
this.emit("focus", treeItem);
},
/**
* Fired on the "link" event for the call tree in this container.
*/
@ -111,12 +142,7 @@ let JsCallTreeView = Heritage.extend(DetailsSubview, {
// Bind events.
root.on("link", this._onLink);
// Pipe "focus" events to the view, mostly for tests
root.on("focus", () => this.emit("focus"));
// TODO tests for optimization event and rendering
// optimization bubbles in call tree
root.on("optimization", (_, node) => this.emit("optimization", node));
root.on("focus", this._onFocus);
// Clear out other call trees.
this.container.innerHTML = "";

View File

@ -88,8 +88,6 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
inverted: inverted,
// Root nodes are hidden in inverted call trees.
hidden: inverted,
// Memory call trees should be sorted by allocations.
sortingPredicate: (a, b) => a.frame.allocations < b.frame.allocations ? 1 : -1,
// Call trees should only auto-expand when not inverted. Passing undefined
// will default to the CALL_TREE_AUTO_EXPAND depth.
autoExpandDepth: inverted ? 0 : undefined,
@ -98,6 +96,12 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
visibleCells: {
selfCount: true,
count: true,
selfSize: true,
size: true,
selfCountPercentage: true,
countPercentage: true,
selfSizePercentage: true,
sizePercentage: true,
function: true
}
});

View File

@ -1,174 +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/. */
"use strict";
let OptimizationsView = Heritage.extend(DetailsSubview, {
rerenderPrefs: [
"show-platform-data",
"flatten-tree-recursion",
],
rangeChangeDebounceTime: 75, // ms
/**
* Sets up the view with event binding.
*/
initialize: function () {
DetailsSubview.initialize.call(this);
this.reset = this.reset.bind(this);
this.tabs = $("#optimizations-tabs");
this._onFramesListSelect = this._onFramesListSelect.bind(this);
OptimizationsListView.initialize();
FramesListView.initialize({ container: $("#frames-tabpanel") });
FramesListView.on("select", this._onFramesListSelect);
},
/**
* Unbinds events.
*/
destroy: function () {
DetailsSubview.destroy.call(this);
this.tabs = this._threadNode = this._frameNode = null;
FramesListView.off("select", this._onFramesListSelect);
FramesListView.destroy();
OptimizationsListView.destroy();
},
/**
* Selects a tab by name.
*
* @param {string} name
* Can be "frames" or "optimizations"
*/
selectTabByName: function (name="frames") {
switch(name) {
case "optimizations":
this.tabs.selectedIndex = 0;
break;
case "frames":
this.tabs.selectedIndex = 1;
break;
}
},
/**
* Method for handling all the set up for rendering a new call tree.
*
* @param object interval [optional]
* The { startTime, endTime }, in milliseconds.
*/
render: function (interval={}) {
let options = {
contentOnly: !PerformanceController.getOption("show-platform-data"),
flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
// Always invert the tree for the optimizations view so we can quickly
// get leaves
invertTree: true,
};
let recording = PerformanceController.getCurrentRecording();
let profile = recording.getProfile();
this.reset();
// TODO bug 1175662
// Share thread nodes between details view
this.threadNode = this._prepareThreadNode(profile, interval, options);
this.emit(EVENTS.OPTIMIZATIONS_RENDERED);
},
/**
* The main thread node used in this recording that contains
* all potential frame nodes to select.
*/
set threadNode(threadNode) {
if (threadNode === this._threadNode) {
return;
}
this._threadNode = threadNode;
// Also clear out the current frame node as its no
// longer relevent
this.frameNode = null;
this._setAndRenderFramesList();
},
get threadNode() {
return this._threadNode;
},
/**
* frameNode is the frame node selected currently to inspect
* the optimization tiers over time and strategies.
*/
set frameNode(frameNode) {
if (frameNode === this._frameNode) {
return;
}
this._frameNode = frameNode;
// If no frame selected, jump to the frame list view. If just selected
// a frame, jump to optimizations view.
// TODO test for this bug 1176056
this.selectTabByName(frameNode ? "optimizations" : "frames");
this._setAndRenderTierGraph();
this._setAndRenderOptimizationsList();
},
get frameNode() {
return this._frameNode;
},
/**
* Clears the frameNode so that tier and opts list
* views are cleared.
*/
reset: function () {
this.threadNode = this.frameNode = null;
},
/**
* Called when the recording is stopped and prepares data to
* populate the graph.
*/
_prepareThreadNode: function (profile, { startTime, endTime }, options) {
let thread = profile.threads[0];
let { contentOnly, invertTree, flattenRecursion } = options;
let threadNode = new ThreadNode(thread, { startTime, endTime, contentOnly, invertTree, flattenRecursion });
return threadNode;
},
/**
* Renders the tier graph.
*/
_setAndRenderTierGraph: function () {
// TODO bug 1150299
},
/**
* Renders the frames list.
*/
_setAndRenderFramesList: function () {
FramesListView.setCurrentThread(this.threadNode);
FramesListView.render();
},
/**
* Renders the optimizations list.
*/
_setAndRenderOptimizationsList: function () {
OptimizationsListView.setCurrentFrame(this.frameNode);
OptimizationsListView.render();
},
/**
* Called when a frame is selected via the FramesListView
*/
_onFramesListSelect: function (_, frameNode) {
this.frameNode = frameNode;
},
toString: () => "[object OptimizationsView]"
});
EventEmitter.decorate(OptimizationsView);

View File

@ -37,11 +37,6 @@ let DetailsView = {
features: ["withAllocations"],
prefs: ["enable-memory-flame"],
},
"optimizations": {
id: "optimizations-view",
view: OptimizationsView,
features: ["withJITOptimizations"],
}
},
/**

View File

@ -1,113 +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/. */
"use strict";
const HTML_NS = "http://www.w3.org/1999/xhtml";
const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
/**
* View for rendering a list of all youngest-frames in a profiler recording.
*/
let FramesListView = {
// Current `<li>` element selected.
_selectedItem: null,
/**
* Initialization function called when the tool starts up.
*/
initialize: function ({ container }) {
this._onFrameListClick = this._onFrameListClick.bind(this);
this.container = container;
this.list = document.createElementNS(HTML_NS, "ul");
this.list.setAttribute("class", "frames-list");
this.list.addEventListener("click", this._onFrameListClick, false);
this.container.appendChild(this.list);
},
/**
* Destruction function called when the tool cleans up.
*/
destroy: function () {
this.list.removeEventListener("click", this._onFrameListClick, false);
this.container.innerHTML = "";
this.container = this.list = null;
},
/**
* Sets the thread node used for subsequent rendering.
*
* @param {ThreadNode} threadNode
*/
setCurrentThread: function (threadNode) {
this.threadNode = threadNode;
},
/**
* Renders a list of leaf frames with optimizations in
* order of hotness from the current ThreadNode.
*/
render: function () {
this.list.innerHTML = "";
if (!this.threadNode) {
return;
}
let totalSamples = this.threadNode.samples;
let sortedFrames = this.threadNode.calls.sort((a, b) => a.youngestFrameSamples < b.youngestFrameSamples ? 1 : -1);
for (let frame of sortedFrames) {
if (!frame.hasOptimizations()) {
continue;
}
let info = frame.getInfo();
let el = document.createElementNS(HTML_NS, "li");
let percentage = frame.youngestFrameSamples / totalSamples * 100;
let percentageText = L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS;
let label = `(${percentageText}) ${info.functionName}`;
el.textContent = label;
el.setAttribute("tooltip", label);
el.setAttribute("data-location", frame.location);
this.list.appendChild(el);
}
},
/**
* Fired when a frame in the list is clicked.
*/
_onFrameListClick: function (e) {
// If no threadNode (no renders), abort;
// also only allow left click to trigger this event
if (!this.threadNode || e.button !== 0) {
return;
}
let target = e.target;
let location = target.getAttribute("data-location");
if (!location) {
return;
}
for (let frame of this.threadNode.calls) {
if (frame.location === location) {
// If found, set the selected class on element, remove it
// from previous element, and emit event "select"
if (this._selectedItem) {
this._selectedItem.classList.remove("selected");
}
this._selectedItem = target;
target.classList.add("selected");
this.emit("select", frame);
break;
}
}
},
toString: () => "[object FramesListView]"
};
EventEmitter.decorate(FramesListView);

View File

@ -360,7 +360,6 @@ let OptimizationsListView = {
},
toString: () => "[object OptimizationsListView]"
};
EventEmitter.decorate(OptimizationsListView);

View File

@ -1,11 +1,12 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
/* globals focusManager, CSSPropertyList, domUtils */
/**
* 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/.
*
* Basic use:
* let spanToEdit = document.getElementById("somespan");
*
@ -48,28 +49,28 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
* Changes will be committed when the InlineEditor's input is blurred
* or dropped when the user presses escape.
*
* @param {object} aOptions
* @param {Object} options
* Options for the editable field, including:
* {Element} element:
* (required) The span to be edited on focus.
* {function} canEdit:
* {Function} canEdit:
* Will be called before creating the inplace editor. Editor
* won't be created if canEdit returns false.
* {function} start:
* {Function} start:
* Will be called when the inplace editor is initialized.
* {function} change:
* {Function} change:
* Will be called when the text input changes. Will be called
* with the current value of the text input.
* {function} done:
* {Function} done:
* Called when input is committed or blurred. Called with
* current value, a boolean telling the caller whether to
* commit the change, and the direction of the next element to be
* selected. Direction may be one of nsIFocusManager.MOVEFOCUS_FORWARD,
* nsIFocusManager.MOVEFOCUS_BACKWARD, or null (no movement).
* This function is called before the editor has been torn down.
* {function} destroy:
* {Function} destroy:
* Called when the editor is destroyed and has been torn down.
* {object} advanceChars:
* {Object} advanceChars:
* This can be either a string or a function.
* If it is a string, then if any characters in it are typed,
* focus will advance to the next element.
@ -78,27 +79,26 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
* and the insertion point. If the function returns true,
* then the focus advance takes place. If it returns false,
* then the character is inserted instead.
* {boolean} stopOnReturn:
* {Boolean} stopOnReturn:
* If true, the return key will not advance the editor to the next
* focusable element.
* {boolean} stopOnTab:
* {Boolean} stopOnTab:
* If true, the tab key will not advance the editor to the next
* focusable element.
* {boolean} stopOnShiftTab:
* {Boolean} stopOnShiftTab:
* If true, shift tab will not advance the editor to the previous
* focusable element.
* {string} trigger: The DOM event that should trigger editing,
* {String} trigger: The DOM event that should trigger editing,
* defaults to "click"
* {boolean} multiline: Should the editor be a multiline textarea?
* {Boolean} multiline: Should the editor be a multiline textarea?
* defaults to false
* {boolean} trimOutput: Should the returned string be trimmed?
* {Boolean} trimOutput: Should the returned string be trimmed?
* defaults to true
*/
function editableField(aOptions)
{
return editableItem(aOptions, function(aElement, aEvent) {
if (!aOptions.element.inplaceEditor) {
new InplaceEditor(aOptions, aEvent);
function editableField(options) {
return editableItem(options, function(element, event) {
if (!options.element.inplaceEditor) {
new InplaceEditor(options, event);
}
});
}
@ -110,25 +110,24 @@ exports.editableField = editableField;
* clicks and sit in the editing tab order, and call
* a callback when it is activated.
*
* @param {object} aOptions
* @param {Object} options
* The options for this editor, including:
* {Element} element: The DOM element.
* {string} trigger: The DOM event that should trigger editing,
* {String} trigger: The DOM event that should trigger editing,
* defaults to "click"
* @param {function} aCallback
* @param {Function} callback
* Called when the editor is activated.
* @return {function} function which calls aCallback
* @return {Function} function which calls callback
*/
function editableItem(aOptions, aCallback)
{
let trigger = aOptions.trigger || "click"
let element = aOptions.element;
function editableItem(options, callback) {
let trigger = options.trigger || "click";
let element = options.element;
element.addEventListener(trigger, function(evt) {
if (evt.target.nodeName !== "a") {
let win = this.ownerDocument.defaultView;
let selection = win.getSelection();
if (trigger != "click" || selection.isCollapsed) {
aCallback(element, evt);
callback(element, evt);
}
evt.stopPropagation();
}
@ -139,7 +138,7 @@ function editableItem(aOptions, aCallback)
element.addEventListener("keypress", function(evt) {
if (evt.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
evt.charCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
aCallback(element);
callback(element);
}
}, true);
@ -168,8 +167,8 @@ function editableItem(aOptions, aCallback)
element._trigger = trigger;
return function turnOnEditMode() {
aCallback(element);
}
callback(element);
};
}
exports.editableItem = this.editableItem;
@ -181,31 +180,32 @@ exports.editableItem = this.editableItem;
* within this JSM. So we provide a little workaround here.
*/
function getInplaceEditorForSpan(aSpan)
{
return aSpan.inplaceEditor;
};
function getInplaceEditorForSpan(span) {
return span.inplaceEditor;
}
exports.getInplaceEditorForSpan = getInplaceEditorForSpan;
function InplaceEditor(aOptions, aEvent)
{
this.elt = aOptions.element;
function InplaceEditor(options, event) {
this.elt = options.element;
let doc = this.elt.ownerDocument;
this.doc = doc;
this.elt.inplaceEditor = this;
this.change = aOptions.change;
this.done = aOptions.done;
this.destroy = aOptions.destroy;
this.initial = aOptions.initial ? aOptions.initial : this.elt.textContent;
this.multiline = aOptions.multiline || false;
this.trimOutput = aOptions.trimOutput === undefined ? true : !!aOptions.trimOutput;
this.stopOnShiftTab = !!aOptions.stopOnShiftTab;
this.stopOnTab = !!aOptions.stopOnTab;
this.stopOnReturn = !!aOptions.stopOnReturn;
this.contentType = aOptions.contentType || CONTENT_TYPES.PLAIN_TEXT;
this.property = aOptions.property;
this.popup = aOptions.popup;
this.change = options.change;
this.done = options.done;
this.destroy = options.destroy;
this.initial = options.initial ? options.initial : this.elt.textContent;
this.multiline = options.multiline || false;
this.trimOutput = options.trimOutput === undefined
? true
: !!options.trimOutput;
this.stopOnShiftTab = !!options.stopOnShiftTab;
this.stopOnTab = !!options.stopOnTab;
this.stopOnReturn = !!options.stopOnReturn;
this.contentType = options.contentType || CONTENT_TYPES.PLAIN_TEXT;
this.property = options.property;
this.popup = options.popup;
this._onBlur = this._onBlur.bind(this);
this._onKeyPress = this._onKeyPress.bind(this);
@ -218,11 +218,11 @@ function InplaceEditor(aOptions, aEvent)
// Pull out character codes for advanceChars, listing the
// characters that should trigger a blur.
if (typeof(aOptions.advanceChars) === "function") {
this._advanceChars = aOptions.advanceChars;
if (typeof options.advanceChars === "function") {
this._advanceChars = options.advanceChars;
} else {
let advanceCharcodes = {};
let advanceChars = aOptions.advanceChars || '';
let advanceChars = options.advanceChars || "";
for (let i = 0; i < advanceChars.length; i++) {
advanceCharcodes[advanceChars.charCodeAt(i)] = true;
}
@ -236,7 +236,7 @@ function InplaceEditor(aOptions, aEvent)
this.input.focus();
if (typeof(aOptions.selectAll) == "undefined" || aOptions.selectAll) {
if (typeof options.selectAll == "undefined" || options.selectAll) {
this.input.select();
}
@ -253,7 +253,7 @@ function InplaceEditor(aOptions, aEvent)
this.input.addEventListener("mousedown",
(e) => { e.stopPropagation(); }, false);
this.validate = aOptions.validate;
this.validate = options.validate;
if (this.validate) {
this.input.addEventListener("keyup", this._onKeyup, false);
@ -261,8 +261,8 @@ function InplaceEditor(aOptions, aEvent)
this._updateSize();
if (aOptions.start) {
aOptions.start(this, aEvent);
if (options.start) {
options.start(this, event);
}
EventEmitter.decorate(this);
@ -279,8 +279,7 @@ InplaceEditor.prototype = {
return val;
},
_createInput: function InplaceEditor_createEditor()
{
_createInput: function() {
this.input =
this.doc.createElementNS(HTML_NS, this.multiline ? "textarea" : "input");
this.input.inplaceEditor = this;
@ -293,8 +292,7 @@ InplaceEditor.prototype = {
/**
* Get rid of the editor.
*/
_clear: function InplaceEditor_clear()
{
_clear: function() {
if (!this.input) {
// Already cleared.
return;
@ -327,8 +325,7 @@ InplaceEditor.prototype = {
* Keeps the editor close to the size of its input string. This is pretty
* crappy, suggestions for improvement welcome.
*/
_autosize: function InplaceEditor_autosize()
{
_autosize: function() {
// Create a hidden, absolutely-positioned span to measure the text
// in the input. Boo.
@ -352,8 +349,7 @@ InplaceEditor.prototype = {
/**
* Clean up the mess created by _autosize().
*/
_stopAutosize: function InplaceEditor_stopAutosize()
{
_stopAutosize: function() {
if (!this._measurement) {
return;
}
@ -364,12 +360,11 @@ InplaceEditor.prototype = {
/**
* Size the editor to fit its current contents.
*/
_updateSize: function InplaceEditor_updateSize()
{
_updateSize: function() {
// Replace spaces with non-breaking spaces. Otherwise setting
// the span's textContent will collapse spaces and the measurement
// will be wrong.
this._measurement.textContent = this.input.value.replace(/ /g, '\u00a0');
this._measurement.textContent = this.input.value.replace(/ /g, "\u00a0");
// We add a bit of padding to the end. Should be enough to fit
// any letter that could be typed, otherwise we'll scroll before
@ -391,8 +386,7 @@ InplaceEditor.prototype = {
* Get the width of a single character in the input to properly position the
* autocompletion popup.
*/
_getInputCharWidth: function InplaceEditor_getInputCharWidth()
{
_getInputCharWidth: function() {
// Just make the text content to be 'x' to get the width of any character in
// a monospace font.
this._measurement.textContent = "x";
@ -402,12 +396,11 @@ InplaceEditor.prototype = {
/**
* Increment property values in rule view.
*
* @param {number} increment
* @param {Number} increment
* The amount to increase/decrease the property value.
* @return {bool} true if value has been incremented.
* @return {Boolean} true if value has been incremented.
*/
_incrementValue: function InplaceEditor_incrementValue(increment)
{
_incrementValue: function(increment) {
let value = this.input.value;
let selectionStart = this.input.selectionStart;
let selectionEnd = this.input.selectionEnd;
@ -434,19 +427,17 @@ InplaceEditor.prototype = {
/**
* Increment the property value based on the property type.
*
* @param {string} value
* @param {String} value
* Property value.
* @param {number} increment
* @param {Number} increment
* Amount to increase/decrease the property value.
* @param {number} selStart
* @param {Number} selStart
* Starting index of the value.
* @param {number} selEnd
* @param {Number} selEnd
* Ending index of the value.
* @return {object} object with properties 'value', 'start', and 'end'.
* @return {Object} object with properties 'value', 'start', and 'end'.
*/
_incrementCSSValue: function InplaceEditor_incrementCSSValue(value, increment,
selStart, selEnd)
{
_incrementCSSValue: function(value, increment, selStart, selEnd) {
let range = this._parseCSSValue(value, selStart);
let type = (range && range.type) || "";
let rawValue = (range ? value.substring(range.start, range.end) : "");
@ -489,11 +480,12 @@ InplaceEditor.prototype = {
}
}
}
return this._incrementGenericValue(value, increment, selStart, selEnd, info);
return this._incrementGenericValue(value, increment, selStart, selEnd,
info);
}
if (incrementedValue === null) {
return;
return null;
}
let preRawValue = value.substr(0, range.start);
@ -509,14 +501,14 @@ InplaceEditor.prototype = {
/**
* Parses the property value and type.
*
* @param {string} value
* @param {String} value
* Property value.
* @param {number} offset
* @param {Number} offset
* Starting index of value.
* @return {object} object with properties 'value', 'start', 'end', and 'type'.
* @return {Object} object with properties 'value', 'start', 'end', and
* 'type'.
*/
_parseCSSValue: function InplaceEditor_parseCSSValue(value, offset)
{
_parseCSSValue: function(value, offset) {
const reSplitCSS = /(url\("?[^"\)]+"?\)?)|(rgba?\([^)]*\)?)|(hsla?\([^)]*\)?)|(#[\dA-Fa-f]+)|(-?\d*\.?\d+(%|[a-z]{1,4})?)|"([^"]*)"?|'([^']*)'?|([^,\s\/!\(\)]+)|(!(.*)?)/;
let start = 0;
let m;
@ -530,7 +522,7 @@ InplaceEditor.prototype = {
}
if (!m) {
return;
return null;
}
let type;
@ -558,22 +550,19 @@ InplaceEditor.prototype = {
* Increment the property value for types other than
* number or hex, such as rgb, hsl, and file names.
*
* @param {string} value
* @param {String} value
* Property value.
* @param {number} increment
* @param {Number} increment
* Amount to increment/decrement.
* @param {number} offset
* @param {Number} offset
* Starting index of the property value.
* @param {number} offsetEnd
* @param {Number} offsetEnd
* Ending index of the property value.
* @param {object} info
* @param {Object} info
* Object with details about the property value.
* @return {object} object with properties 'value', 'start', and 'end'.
* @return {Object} object with properties 'value', 'start', and 'end'.
*/
_incrementGenericValue:
function InplaceEditor_incrementGenericValue(value, increment, offset,
offsetEnd, info)
{
_incrementGenericValue: function(value, increment, offset, offsetEnd, info) {
// Try to find a number around the cursor to increment.
let start, end;
// Check if we are incrementing in a non-number context (such as a URL)
@ -585,8 +574,8 @@ InplaceEditor.prototype = {
start = offset;
end = offsetEnd;
} else {
// Parse periods as belonging to the number only if we are in a known number
// context. (This makes incrementing the 1 in 'image1.gif' work.)
// Parse periods as belonging to the number only if we are in a known
// number context. (This makes incrementing the 1 in 'image1.gif' work.)
let pattern = "[" + (info ? "0-9." : "0-9") + "]*";
let before = new RegExp(pattern + "$").exec(value.substr(0, offset))[0].length;
let after = new RegExp("^" + pattern).exec(value.substr(offset))[0].length;
@ -602,8 +591,7 @@ InplaceEditor.prototype = {
}
}
if (start !== end)
{
if (start !== end) {
// Include percentages as part of the incremented number (they are
// common enough).
if (value.charAt(end) === "%") {
@ -629,17 +617,15 @@ InplaceEditor.prototype = {
/**
* Increment the property value for numbers.
*
* @param {string} rawValue
* @param {String} rawValue
* Raw value to increment.
* @param {number} increment
* @param {Number} increment
* Amount to increase/decrease the raw value.
* @param {object} info
* @param {Object} info
* Object with info about the property value.
* @return {string} the incremented value.
* @return {String} the incremented value.
*/
_incrementRawValue:
function InplaceEditor_incrementRawValue(rawValue, increment, info)
{
_incrementRawValue: function(rawValue, increment, info) {
let num = parseFloat(rawValue);
if (isNaN(num)) {
@ -667,25 +653,23 @@ InplaceEditor.prototype = {
/**
* Increment the property value for hex.
*
* @param {string} value
* @param {String} value
* Property value.
* @param {number} increment
* @param {Number} increment
* Amount to increase/decrease the property value.
* @param {number} offset
* @param {Number} offset
* Starting index of the property value.
* @param {number} offsetEnd
* @param {Number} offsetEnd
* Ending index of the property value.
* @return {object} object with properties 'value' and 'selection'.
* @return {Object} object with properties 'value' and 'selection'.
*/
_incHexColor:
function InplaceEditor_incHexColor(rawValue, increment, offset, offsetEnd)
{
_incHexColor: function(rawValue, increment, offset, offsetEnd) {
// Return early if no part of the rawValue is selected.
if (offsetEnd > rawValue.length && offset >= rawValue.length) {
return;
return null;
}
if (offset < 1 && offsetEnd <= 1) {
return;
return null;
}
// Ignore the leading #.
rawValue = rawValue.substr(1);
@ -707,7 +691,7 @@ InplaceEditor.prototype = {
}
if (rawValue.length !== 6) {
return;
return null;
}
// If no selection, increment an adjacent color, preferably one to the left.
@ -724,7 +708,7 @@ InplaceEditor.prototype = {
offsetEnd += offsetEnd % 2;
// Remap the increments from [0.1, 1, 10] to [1, 1, 16].
if (-1 < increment && increment < 1) {
if (increment > -1 && increment < 1) {
increment = (increment < 0 ? -1 : 1);
}
if (Math.abs(increment) === 10) {
@ -739,7 +723,7 @@ InplaceEditor.prototype = {
let value = parseInt(mid, 16);
if (isNaN(value)) {
return;
return null;
}
mid = Math.min(Math.max(value + increment, 0), 255).toString(16);
@ -763,43 +747,45 @@ InplaceEditor.prototype = {
/**
* Cycle through the autocompletion suggestions in the popup.
*
* @param {boolean} aReverse
* @param {Boolean} reverse
* true to select previous item from the popup.
* @param {boolean} aNoSelect
* @param {Boolean} noSelect
* true to not select the text after selecting the newly selectedItem
* from the popup.
*/
_cycleCSSSuggestion:
function InplaceEditor_cycleCSSSuggestion(aReverse, aNoSelect)
{
_cycleCSSSuggestion: function(reverse, noSelect) {
// selectedItem can be null when nothing is selected in an empty editor.
let {label, preLabel} = this.popup.selectedItem || {label: "", preLabel: ""};
if (aReverse) {
let {label, preLabel} = this.popup.selectedItem ||
{label: "", preLabel: ""};
if (reverse) {
this.popup.selectPreviousItem();
} else {
this.popup.selectNextItem();
}
this._selectedIndex = this.popup.selectedIndex;
let input = this.input;
let pre = "";
if (input.selectionStart < input.selectionEnd) {
pre = input.value.slice(0, input.selectionStart);
}
else {
} else {
pre = input.value.slice(0, input.selectionStart - label.length +
preLabel.length);
preLabel.length);
}
let post = input.value.slice(input.selectionEnd, input.value.length);
let item = this.popup.selectedItem;
let toComplete = item.label.slice(item.preLabel.length);
input.value = pre + toComplete + post;
if (!aNoSelect) {
if (!noSelect) {
input.setSelectionRange(pre.length, pre.length + toComplete.length);
}
else {
} else {
input.setSelectionRange(pre.length + toComplete.length,
pre.length + toComplete.length);
}
this._updateSize();
// This emit is mainly for the purpose of making the test flow simpler.
this.emit("after-suggest");
@ -808,10 +794,9 @@ InplaceEditor.prototype = {
/**
* Call the client's done handler and clear out.
*/
_apply: function InplaceEditor_apply(aEvent, direction)
{
_apply: function(event, direction) {
if (this._applied) {
return;
return null;
}
this._applied = true;
@ -827,25 +812,26 @@ InplaceEditor.prototype = {
/**
* Handle loss of focus by calling done if it hasn't been called yet.
*/
_onBlur: function InplaceEditor_onBlur(aEvent, aDoNotClear)
{
if (aEvent && this.popup && this.popup.isOpen &&
_onBlur: function(event, doNotClear) {
if (event && this.popup && this.popup.isOpen &&
this.popup.selectedIndex >= 0) {
let label, preLabel;
if (this._selectedIndex === undefined) {
({label, preLabel} = this.popup.getItemAtIndex(this.popup.selectedIndex));
}
else {
({label, preLabel} =
this.popup.getItemAtIndex(this.popup.selectedIndex));
} else {
({label, preLabel} = this.popup.getItemAtIndex(this._selectedIndex));
}
let input = this.input;
let pre = "";
if (input.selectionStart < input.selectionEnd) {
pre = input.value.slice(0, input.selectionStart);
}
else {
} else {
pre = input.value.slice(0, input.selectionStart - label.length +
preLabel.length);
preLabel.length);
}
let post = input.value.slice(input.selectionEnd, input.value.length);
let item = this.popup.selectedItem;
@ -873,8 +859,10 @@ InplaceEditor.prototype = {
}
return;
}
this._apply();
if (!aDoNotClear) {
if (!doNotClear) {
this._clear();
}
},
@ -882,8 +870,7 @@ InplaceEditor.prototype = {
/**
* Handle the input field's keypress event.
*/
_onKeyPress: function InplaceEditor_onKeyPress(aEvent)
{
_onKeyPress: function(event) {
let prevent = false;
const largeIncrement = 100;
@ -892,35 +879,35 @@ InplaceEditor.prototype = {
let increment = 0;
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
increment = 1;
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
increment = -1;
}
if (aEvent.shiftKey && !aEvent.altKey) {
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
if (event.shiftKey && !event.altKey) {
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
increment *= largeIncrement;
} else {
increment *= mediumIncrement;
}
} else if (aEvent.altKey && !aEvent.shiftKey) {
} else if (event.altKey && !event.shiftKey) {
increment *= smallIncrement;
}
// Use default cursor movement rather than providing auto-suggestions.
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
this._preventSuggestions = true;
}
let cycling = false;
if (increment && this._incrementValue(increment) ) {
if (increment && this._incrementValue(increment)) {
this._updateSize();
prevent = true;
cycling = true;
@ -931,30 +918,30 @@ InplaceEditor.prototype = {
this._doValidation();
}
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_BACK_SPACE ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DELETE ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_LEFT ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RIGHT) {
if (this.popup && this.popup.isOpen) {
this.popup.hidePopup();
}
} else if (!cycling && !aEvent.metaKey && !aEvent.altKey && !aEvent.ctrlKey) {
} else if (!cycling && !event.metaKey && !event.altKey && !event.ctrlKey) {
this._maybeSuggestCompletion();
}
if (this.multiline &&
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
aEvent.shiftKey) {
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN &&
event.shiftKey) {
prevent = false;
} else if (this._advanceChars(aEvent.charCode, this.input.value,
this.input.selectionStart)
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN
|| aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
} else if (this._advanceChars(event.charCode, this.input.value,
this.input.selectionStart) ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN ||
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB) {
prevent = true;
let direction = FOCUS_FORWARD;
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
aEvent.shiftKey) {
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
event.shiftKey) {
if (this.stopOnShiftTab) {
direction = null;
} else {
@ -962,9 +949,9 @@ InplaceEditor.prototype = {
}
}
if ((this.stopOnReturn &&
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
(this.stopOnTab && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
!aEvent.shiftKey)) {
event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
(this.stopOnTab && event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
!event.shiftKey)) {
direction = null;
}
@ -979,22 +966,21 @@ InplaceEditor.prototype = {
let input = this.input;
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
this.contentType == CONTENT_TYPES.CSS_MIXED) {
if (this.popup && input.selectionStart < input.selectionEnd) {
aEvent.preventDefault();
event.preventDefault();
input.setSelectionRange(input.selectionEnd, input.selectionEnd);
this.emit("after-suggest");
return;
}
else if (this.popup && this.popup.isOpen) {
aEvent.preventDefault();
this._cycleCSSSuggestion(aEvent.shiftKey, true);
} else if (this.popup && this.popup.isOpen) {
event.preventDefault();
this._cycleCSSSuggestion(event.shiftKey, true);
return;
}
}
this._apply(aEvent, direction);
this._apply(event, direction);
// Close the popup if open
if (this.popup && this.popup.isOpen) {
@ -1009,14 +995,14 @@ InplaceEditor.prototype = {
// If the next node to be focused has been tagged as an editable
// node, trigger editing using the configured event
if (next && next.ownerDocument === this.doc && next._editable) {
let e = this.doc.createEvent('Event');
let e = this.doc.createEvent("Event");
e.initEvent(next._trigger, true, true);
next.dispatchEvent(e);
}
}
this._clear();
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE) {
// Cancel and blur ourselves.
// Now we don't want to suggest anything as we are moving out.
this._preventSuggestions = true;
@ -1028,8 +1014,8 @@ InplaceEditor.prototype = {
this.cancelled = true;
this._apply();
this._clear();
aEvent.stopPropagation();
} else if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
event.stopPropagation();
} else if (event.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_SPACE) {
// No need for leading spaces here. This is particularly
// noticable when adding a property: it's very natural to type
// <name>: (which advances to the next property) then spacebar.
@ -1037,22 +1023,21 @@ InplaceEditor.prototype = {
}
if (prevent) {
aEvent.preventDefault();
event.preventDefault();
}
},
/**
* Handle the input field's keyup event.
*/
_onKeyup: function(aEvent) {
_onKeyup: function() {
this._applied = false;
},
/**
* Handle changes to the input text.
*/
_onInput: function InplaceEditor_onInput(aEvent)
{
_onInput: function() {
// Validate the entered value.
this._doValidation();
@ -1070,8 +1055,7 @@ InplaceEditor.prototype = {
/**
* Fire validation callback with current input
*/
_doValidation: function()
{
_doValidation: function() {
if (this.validate && this.input) {
this.validate(this.input.value);
}
@ -1080,10 +1064,10 @@ InplaceEditor.prototype = {
/**
* Handles displaying suggestions based on the current input.
*
* @param {boolean} aNoAutoInsert
* @param {Boolean} noAutoInsert
* true if you don't want to automatically insert the first suggestion
*/
_maybeSuggestCompletion: function(aNoAutoInsert) {
_maybeSuggestCompletion: function(noAutoInsert) {
// Input can be null in cases when you intantaneously switch out of it.
if (!this.input) {
return;
@ -1135,7 +1119,8 @@ InplaceEditor.prototype = {
}
list =
["!important", ...domUtils.getCSSValuesForProperty(this.property.name)];
["!important",
...domUtils.getCSSValuesForProperty(this.property.name)];
if (query == "") {
// Do not suggest '!important' without any manually typed character.
@ -1150,7 +1135,8 @@ InplaceEditor.prototype = {
let propertyName =
query.match(/[;"'=]\s*([^"';:= ]+)\s*:\s*[^"';:=]*$/)[1];
list =
["!important;", ...domUtils.getCSSValuesForProperty(propertyName)];
["!important;",
...domUtils.getCSSValuesForProperty(propertyName)];
let matchLastQuery = /([^\s,.\/]+$)/.exec(match[2] || "");
if (matchLastQuery) {
startCheckQuery = matchLastQuery[0];
@ -1172,7 +1158,7 @@ InplaceEditor.prototype = {
}
}
}
if (!aNoAutoInsert) {
if (!noAutoInsert) {
list.some(item => {
if (startCheckQuery != null && item.startsWith(startCheckQuery)) {
input.value = query + item.slice(startCheckQuery.length) +
@ -1199,13 +1185,11 @@ InplaceEditor.prototype = {
preLabel: startCheckQuery,
label: list[i]
});
}
else if (count > 0) {
} else if (count > 0) {
// Since count was incremented, we had already crossed the entries
// which would have started with query, assuming that list is sorted.
break;
}
else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
} else if (startCheckQuery != null && list[i][0] > startCheckQuery[0]) {
// We have crossed all possible matches alphabetically.
break;
}
@ -1217,7 +1201,7 @@ InplaceEditor.prototype = {
this.inputCharWidth;
this.popup.setItems(finalList);
this.popup.openPopup(this.input, x);
if (aNoAutoInsert) {
if (noAutoInsert) {
this.popup.selectedIndex = -1;
}
} else {
@ -1233,25 +1217,22 @@ InplaceEditor.prototype = {
/**
* Copy text-related styles from one element to another.
*/
function copyTextStyles(aFrom, aTo)
{
let win = aFrom.ownerDocument.defaultView;
let style = win.getComputedStyle(aFrom);
aTo.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
aTo.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
aTo.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
aTo.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
function copyTextStyles(from, to) {
let win = from.ownerDocument.defaultView;
let style = win.getComputedStyle(from);
to.style.fontFamily = style.getPropertyCSSValue("font-family").cssText;
to.style.fontSize = style.getPropertyCSSValue("font-size").cssText;
to.style.fontWeight = style.getPropertyCSSValue("font-weight").cssText;
to.style.fontStyle = style.getPropertyCSSValue("font-style").cssText;
}
/**
* Trigger a focus change similar to pressing tab/shift-tab.
*/
function moveFocus(aWin, aDirection)
{
return focusManager.moveFocus(aWin, null, aDirection, 0);
function moveFocus(win, direction) {
return focusManager.moveFocus(win, null, direction, 0);
}
XPCOMUtils.defineLazyGetter(this, "focusManager", function() {
return Services.focus;
});

View File

@ -33,6 +33,10 @@ function* getVariablesView(hud) {
}
let deferred = promise.defer();
// Filter out other messages to ensure ours stays visible.
hud.ui.filterBox.value = "browser_console_hide_jsterm_test";
hud.jsterm.clearOutput();
hud.jsterm.execute("new Object({ browser_console_hide_jsterm_test: true })");

View File

@ -23,7 +23,8 @@ marker.label.parseHTML=Parse HTML
marker.label.parseXML=Parse XML
marker.label.domevent=DOM Event
marker.label.consoleTime=Console
marker.label.garbageCollection=Incremental GC
marker.label.garbageCollection2=Garbage Collection
marker.label.garbageCollection.incremental=Incremental GC
marker.label.garbageCollection.nonIncremental=Non-incremental GC
marker.label.cycleCollection=Cycle Collection
marker.label.cycleCollection.forgetSkippable=CC Graph Reduction

View File

@ -92,13 +92,20 @@ category.storage=Storage
category.events=Input & Events
category.tools=Tools
# LOCALIZATION NOTE (table.ms):
# This string is displayed in the call tree after units of time in milliseconds.
table.ms=ms
# LOCALIZATION NOTE (table.bytes):
# This string is displayed in the call tree after bytesize units.
# %S represents the value in bytes.
table.bytes=%S B
# LOCALIZATION NOTE (table.percentage):
# LOCALIZATION NOTE (table.ms2):
# This string is displayed in the call tree after units of time in milliseconds.
# %S represents the value in milliseconds.
table.ms2=%S ms
# LOCALIZATION NOTE (table.percentage2):
# This string is displayed in the call tree after units representing percentages.
table.percentage=%
# %S represents the value in percentage with two decimal points, localized.
table.percentage2=%S%
# LOCALIZATION NOTE (table.root):
# This string is displayed in the call tree for the root node.
@ -113,10 +120,10 @@ table.idle=(idle)
# labels which, when clicked, jump to the debugger.
table.url.tooltiptext=View source in Debugger
# LOCALIZATION NOTE (table.view-optimizations.tooltiptext):
# LOCALIZATION NOTE (table.view-optimizations.tooltiptext2):
# This string is displayed in the icon displayed next to frames that
# have optimization data
table.view-optimizations.tooltiptext=View optimizations in JIT View
table.view-optimizations.tooltiptext2=Frame contains JIT optimization data
# LOCALIZATION NOTE (recordingsList.importDialogTitle):
# This string is displayed as a title for importing a recoring from disk.
@ -165,4 +172,4 @@ timeline.records=RECORDS
# %S is the percentage of the buffer used -- there are two "%"s after to escape
# the % that is actually displayed.
# Example: "Buffer 54% full"
profiler.bufferFull=Buffer %S%% full
profiler.bufferFull=Buffer %S%% full

View File

@ -17,6 +17,7 @@ sourceName360se=360 Secure Browser
importedBookmarksFolder=From %S
importedSafariReadingList=Reading List (From Safari)
importedEdgeReadingList=Reading List (From Edge)
# Import Sources
# Note: When adding an import source for profile reset, add the string name to

View File

@ -234,8 +234,20 @@
.call-tree-header[type="count"],
.call-tree-cell[type="count"],
.call-tree-header[type="self-count"],
.call-tree-cell[type="self-count"] {
width: 9vw;
.call-tree-cell[type="self-count"],
.call-tree-header[type="size"],
.call-tree-cell[type="size"],
.call-tree-header[type="self-size"],
.call-tree-cell[type="self-size"],
.call-tree-header[type="count-percentage"],
.call-tree-cell[type="count-percentage"],
.call-tree-header[type="self-count-percentage"],
.call-tree-cell[type="self-count-percentage"],
.call-tree-header[type="size-percentage"],
.call-tree-cell[type="size-percentage"],
.call-tree-header[type="self-size-percentage"],
.call-tree-cell[type="self-size-percentage"] {
width: 6vw;
}
.call-tree-header[type="function"],
@ -685,9 +697,6 @@ description.opt-icon::before {
.opt-icon[severity=warning]::before {
background-position: -24px -24px;
}
.opt-icon[type=linkable]::before {
cursor: pointer;
}
ul.frames-list {
list-style-type: none;

View File

@ -18,11 +18,16 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
this.EXPORTED_SYMBOLS = ["Langpacks"];
let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
? (aMsg) => {
dump("-*-*- Langpacks: " + aMsg + "\n");
}
: (aMsg) => {};
let debug;
function debugPrefObserver() {
debug = Services.prefs.getBoolPref("dom.mozApps.debug")
? (aMsg) => {
dump("-*-*- Langpacks: " + aMsg + "\n");
}
: (aMsg) => {};
}
debugPrefObserver();
Services.prefs.addObserver("dom.mozApps.debug", debugPrefObserver, false);
/**
* Langpack support

View File

@ -107,10 +107,14 @@ let debug = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
.AndroidLog.d.bind(null, "Webapps");
#else
// Elsewhere, report debug messages only if dom.mozApps.debug is set to true.
// The pref is only checked once, on startup, so restart after changing it.
let debug = Services.prefs.getBoolPref("dom.mozApps.debug")
? (aMsg) => dump("-*- Webapps.jsm : " + aMsg + "\n")
: (aMsg) => {};
let debug;
function debugPrefObserver() {
debug = Services.prefs.getBoolPref("dom.mozApps.debug")
? (aMsg) => dump("-*- Webapps.jsm : " + aMsg + "\n")
: (aMsg) => {};
}
debugPrefObserver();
Services.prefs.addObserver("dom.mozApps.debug", debugPrefObserver, false);
#endif
function getNSPRErrorCode(err) {

View File

@ -2,6 +2,7 @@
skip-if = buildapp == 'b2g' || os == 'android'
support-files =
asmjs/*
common.js
file_bug_945152.html
file_bug_945152.sjs

3
dom/apps/tests/common.js Normal file
View File

@ -0,0 +1,3 @@
function prepareEnv(cb) {
SpecialPowers.pushPrefEnv({"set":[["dom.mozApps.debug", true]]}, cb);
}

View File

@ -8,6 +8,7 @@ support-files =
addons/update.webapp^headers^
addons/index.html
chromeAddCert.js
common.js
file_app.sjs
file_app.template.html
file_script.template.js

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1042881
<title>Test for Bug 923897 - Test apps as addons</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript;version=1.7">
/**
@ -203,7 +204,7 @@ function runTest() {
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1XXXXXX}
<title>Test for Bug {1072090}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -121,7 +122,7 @@ function runTest() {
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
<meta charset="utf-8">
<title>Test for Bug 826058</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
@ -278,7 +279,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=826058">Mozilla Bug 826058</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=863337">Mozilla Bug 863337</a>
<p id="display"></p>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1168300
<meta charset="utf-8">
<title>Test for Bug 1168300</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
@ -111,7 +112,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1168300
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1168300">Mozilla Bug 1168300</a>
<p id="display"></p>
<div id="content" style="display: none">

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=795164
<meta charset="utf-8">
<title>Test for Bug 795164</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
@ -96,7 +97,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=795164
}
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795164">Mozilla Bug 795164</a>
<p id="display"></p>
<div id="content" style="display: none">

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
<meta charset="utf-8">
<title>Test for Bug 945152</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
@ -162,7 +163,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=945152">Mozilla Bug 945152</a>
<p id="display"></p>
<div id="content" style="display: none">

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1191516}
<title>Test for Bug {1191516}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -92,7 +93,7 @@ function runTest() {
yield undefined;
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={982874}
<title>Test for Bug {982874}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -322,7 +323,7 @@ function runTest() {
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1111961}
<title>Test for Bug {1111961}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -114,7 +115,7 @@ function runTest() {
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={778277}
<title>Test for Bug {778277}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -116,7 +117,7 @@ function runTest() {
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={960837}
<title>Test for Bug {960837}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -206,7 +207,7 @@ function runTest() {
yield undefined;
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1108096
<title>Test for Bug 1108096 - Langpack support</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript;version=1.7">
/**
@ -305,7 +306,7 @@ function runTest() {
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -9,6 +9,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=989806
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -341,7 +342,7 @@ PackagedTestHelper.setSteps([
}
]);
addLoadEvent(PackagedTestHelper.start);
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
</script>
</pre>

View File

@ -212,6 +212,9 @@ function checkAppState(aApp,
}
var steps = [
function() {
prepareEnv(next);
},
function() {
setupDataDirs(next);
ok(true, "Data directory set up to " + singlevariantDir);

View File

@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=893800
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common.js"/>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">

View File

@ -10,6 +10,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=997886
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/chrome-harness.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript;version=1.7">
@ -229,7 +230,7 @@ function runTest() {
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<p id="display"></p>
<div id="content" style="display: none">
</div>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={821589}
<title>Test for Bug {821589} Packaged apps installation and update</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -347,7 +348,7 @@ var steps = [
PackagedTestHelper.setSteps(steps);
addLoadEvent(PackagedTestHelper.start);
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={900533}
<title>Test for Bug {900533} Packaged app update tests</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -346,7 +347,7 @@ PackagedTestHelper.setSteps(steps);
// install tests
miniManifestURL = PackagedTestHelper.gSJS + "?getManifest=true&appToUpdate&testNameChange";
addLoadEvent(PackagedTestHelper.start);
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={757226}
<title>Test for Bug {757226} Implement mozApps app.replaceReceipt</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -231,7 +232,7 @@ function runTest() {
ok(true, "App uninstalled");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=880043
<title>Test for Bug 880043 Packaged apps installation and update</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -269,7 +270,7 @@ var steps = [
PackagedTestHelper.setSteps(steps);
PackagedTestHelper.gSJSPath = gSJSPath;
addLoadEvent(PackagedTestHelper.start);
addLoadEvent(() => prepareEnv(() => PackagedTestHelper.start()));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1011738}
<title>Test for Bug {1011738}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript" src="test_packaged_app_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -102,7 +103,7 @@ function runTest() {
yield undefined;
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1097468}
<title>Test for Bug {1097468}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -192,7 +193,7 @@ function runTest() {
navigator.mozApps.mgmt.onuninstall = null;
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -8,6 +8,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=830258
<title>Test for Bug 830258</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="common.js"></script>
<script type="application/javascript;version=1.7">
/** Test for Bug 830258 **/
@ -96,7 +97,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=830258
}
</script>
</head>
<body onload="go()">
<body onload="prepareEnv(go)">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=830258">Mozilla Bug 830258</a>
<p id="display"></p>
<div id="content" style="display: none">

View File

@ -7,6 +7,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id={1075716}
<title>Install web app from manifest with application/manifest+json MIME type</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
@ -165,7 +166,7 @@ function runTest() {
is(request.result.length, initialAppsCount, "Correct number of apps.");
}
addLoadEvent(go);
addLoadEvent(() => prepareEnv(go));
</script>
</pre>

View File

@ -5,6 +5,7 @@
<title>Test for Widget</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="file_test_widget.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
@ -12,7 +13,7 @@
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
gHasBrowserPermission = false;
runTest();
prepareEnv(runTest);
</script>
</body>
</html>

View File

@ -5,6 +5,7 @@
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="file_test_widget.js"></script>
<script type="application/javascript" src="common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
@ -12,7 +13,7 @@
<script type="application/javascript;version=1.7">
SimpleTest.waitForExplicitFinish();
gHasBrowserPermission = true;
runTest();
prepareEnv(runTest);
</script>
</body>
</html>

View File

@ -0,0 +1,4 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/Services.jsm");
var dom_mozApps_debug = Services.prefs.getBoolPref("dom.mozApps.debug");
Services.prefs.setBoolPref("dom.mozApps.debug", true);

View File

@ -0,0 +1 @@
Services.prefs.setBoolPref("dom.mozApps.debug", dom_mozApps_debug);

View File

@ -1,10 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/AppsUtils.jsm");
Cu.import("resource:///modules/Services.jsm");
add_test(function test_has_widget_criterion() {

View File

@ -1,9 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/InterAppCommService.jsm");
Cu.import("resource://gre/modules/AppConstants.jsm");

View File

@ -1,8 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/AppsUtils.jsm");
add_test(() => {

View File

@ -1,6 +1,6 @@
[DEFAULT]
head =
tail =
head = head.js
tail = tail.js
[test_has_widget_criterion.js]
[test_inter_app_comm_service.js]

View File

@ -271,8 +271,6 @@ user_pref("browser.translation.engine", "bing");
// Make sure we don't try to load snippets from the network.
user_pref("browser.aboutHomeSnippets.updateUrl", "nonexistent://test");
// Enable debug logging in the mozApps implementation.
user_pref("dom.mozApps.debug", true);
// Enable apps customizations
user_pref("dom.apps.customization.enabled", true);

View File

@ -66,6 +66,13 @@ const standardParams = {
description: l10n.lookup("screenshotDelayDesc"),
manual: l10n.lookup("screenshotDelayManual")
},
{
name: "dpi",
type: { name: "number", min: 0, allowFloat: true },
defaultValue: 0,
description: l10n.lookup("screenshotDPIDesc"),
manual: l10n.lookup("screenshotDPIManual")
},
{
name: "fullpage",
type: "boolean",
@ -287,7 +294,7 @@ function createScreenshotData(document, args) {
const canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
const ctx = canvas.getContext("2d");
const ratio = window.devicePixelRatio;
const ratio = args.dpi ? args.dpi : window.devicePixelRatio;
canvas.width = width * ratio;
canvas.height = height * ratio;
ctx.scale(ratio, ratio);

View File

@ -211,7 +211,12 @@ const PerformanceFront = exports.PerformanceFront = protocol.FrontClass(Performa
let normalizedCurrent = (totalSize * (currentGeneration - origGeneration)) + currentPosition;
let percent = (normalizedCurrent - origPosition) / totalSize;
return percent > 1 ? 1 : percent;
// Clamp between 0 and 1; can get negative percentage values when a new
// recording starts and the currentBufferStatus has not yet been updated. Rather
// than fetching another status update, just clamp to 0, and this will be updated
// on the next profiler-status event.
return percent > 1 ? 1 : percent < 0 ? 0 : percent;
},
/**

View File

@ -1555,3 +1555,104 @@ function getFontPreviewData(font, doc, options) {
}
exports.getFontPreviewData = getFontPreviewData;
/**
* Get the text content of a rule given some CSS text, a line and a column
* Consider the following example:
* body {
* color: red;
* }
* p {
* line-height: 2em;
* color: blue;
* }
* Calling the function with the whole text above and line=4 and column=1 would
* return "line-height: 2em; color: blue;"
* @param {String} initialText
* @param {Number} line (1-indexed)
* @param {Number} column (1-indexed)
* @return {object} An object of the form {offset: number, text: string}
* The offset is the index into the input string where
* the rule text started. The text is the content of
* the rule.
*/
function getRuleText(initialText, line, column) {
if (typeof line === "undefined" || typeof column === "undefined") {
throw new Error("Location information is missing");
}
let {offset: textOffset, text} =
getTextAtLineColumn(initialText, line, column);
let lexer = DOMUtils.getCSSLexer(text);
// Search forward for the opening brace.
while (true) {
let token = lexer.nextToken();
if (!token) {
throw new Error("couldn't find start of the rule");
}
if (token.tokenType === "symbol" && token.text === "{") {
break;
}
}
// Now collect text until we see the matching close brace.
let braceDepth = 1;
let startOffset, endOffset;
while (true) {
let token = lexer.nextToken();
if (!token) {
break;
}
if (startOffset === undefined) {
startOffset = token.startOffset;
}
if (token.tokenType === "symbol") {
if (token.text === "{") {
++braceDepth;
} else if (token.text === "}") {
--braceDepth;
if (braceDepth == 0) {
break;
}
}
}
endOffset = token.endOffset;
}
// If the rule was of the form "selector {" with no closing brace
// and no properties, just return an empty string.
if (startOffset === undefined) {
return {offset: 0, text: ""};
}
// Note that this approach will preserve comments, despite the fact
// that cssTokenizer skips them.
return {offset: textOffset + startOffset,
text: text.substring(startOffset, endOffset)};
}
exports.getRuleText = getRuleText;
/**
* Return the offset and substring of |text| that starts at the given
* line and column.
* @param {String} text
* @param {Number} line (1-indexed)
* @param {Number} column (1-indexed)
* @return {object} An object of the form {offset: number, text: string},
* where the offset is the offset into the input string
* where the text starts, and where text is the text.
*/
function getTextAtLineColumn(text, line, column) {
let offset;
if (line > 1) {
let rx = new RegExp("(?:.*(?:\\r\\n|\\n|\\r|\\f)){" + (line - 1) + "}");
offset = rx.exec(text)[0].length;
} else {
offset = 0;
}
offset += column - 1;
return {offset: offset, text: text.substr(offset) };
}
exports.getTextAtLineColumn = getTextAtLineColumn;

View File

@ -0,0 +1,130 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {getRuleText} = devtools.require("devtools/server/actors/styles");
const TEST_DATA = [
{
desc: "Empty input",
input: "",
line: 1,
column: 1,
throws: true
},
{
desc: "Simplest test case",
input: "#id{color:red;background:yellow;}",
line: 1,
column: 1,
expected: {offset: 4, text: "color:red;background:yellow;"}
},
{
desc: "Multiple rules test case",
input: "#id{color:red;background:yellow;}.class-one .class-two { position:absolute; line-height: 45px}",
line: 1,
column: 34,
expected: {offset: 56, text: " position:absolute; line-height: 45px"}
},
{
desc: "Unclosed rule",
input: "#id{color:red;background:yellow;",
line: 1,
column: 1,
expected: {offset: 4, text: "color:red;background:yellow;"}
},
{
desc: "Null input",
input: null,
line: 1,
column: 1,
throws: true
},
{
desc: "Missing loc",
input: "#id{color:red;background:yellow;}",
throws: true
},
{
desc: "Multi-lines CSS",
input: [
"/* this is a multi line css */",
"body {",
" color: green;",
" background-repeat: no-repeat",
"}",
" /*something else here */",
"* {",
" color: purple;",
"}"
].join("\n"),
line: 7,
column: 1,
expected: {offset: 116, text: "\n color: purple;\n"}
},
{
desc: "Multi-lines CSS and multi-line rule",
input: [
"/* ",
"* some comments",
"*/",
"",
"body {",
" margin: 0;",
" padding: 15px 15px 2px 15px;",
" color: red;",
"}",
"",
"#header .btn, #header .txt {",
" font-size: 100%;",
"}",
"",
"#header #information {",
" color: #dddddd;",
" font-size: small;",
"}",
].join("\n"),
line: 5,
column: 1,
expected: {
offset: 30,
text: "\n margin: 0;\n padding: 15px 15px 2px 15px;\n color: red;\n"}
},
{
desc: "Content string containing a } character",
input: " #id{border:1px solid red;content: '}';color:red;}",
line: 1,
column: 4,
expected: {offset: 7, text: "border:1px solid red;content: '}';color:red;"}
},
];
function run_test() {
for (let test of TEST_DATA) {
do_print("Starting test: " + test.desc);
do_print("Input string " + test.input);
let output;
try {
output = getRuleText(test.input, test.line, test.column);
if (test.throws) {
do_print("Test should have thrown");
do_check_true(false);
}
} catch (e) {
do_print("getRuleText threw an exception with the given input string");
if (test.throws) {
do_print("Exception expected");
do_check_true(true);
} else {
do_print("Exception unexpected\n" + e);
do_check_true(false);
}
}
if (output) {
deepEqual(output, test.expected);
}
}
}

View File

@ -0,0 +1,35 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {getTextAtLineColumn} = devtools.require("devtools/server/actors/styles");
const TEST_DATA = [
{
desc: "simplest",
input: "#id{color:red;background:yellow;}",
line: 1,
column: 5,
expected: {offset: 4, text: "color:red;background:yellow;}"}
},
{
desc: "multiple lines",
input: "one\n two\n three",
line: 3,
column: 3,
expected: {offset: 11, text: "three"}
},
];
function run_test() {
for (let test of TEST_DATA) {
do_print("Starting test: " + test.desc);
do_print("Input string " + test.input);
let output = getTextAtLineColumn(test.input, test.line, test.column);
deepEqual(output, test.expected);
}
}

View File

@ -78,6 +78,8 @@ skip-if = os == 'linux' # Bug 1176173
[test_frameactor-04.js]
[test_frameactor-05.js]
[test_framearguments-01.js]
[test_getRuleText.js]
[test_getTextAtLineColumn.js]
[test_pauselifetime-01.js]
[test_pauselifetime-02.js]
[test_pauselifetime-03.js]

View File

@ -96,6 +96,16 @@ screenshotDelayDesc=Delay (seconds)
# asks for help on what it does.
screenshotDelayManual=The time to wait (in seconds) before the screenshot is taken
# LOCALIZATION NOTE (screenshotDPIDesc) A very short string to describe
# the 'dpi' parameter to the 'screenshot' command, which is displayed in
# a dialog when the user is using this command.
screenshotDPIDesc=Dots per inch
# LOCALIZATION NOTE (screenshotDPIManual) A fuller description of the
# 'dpi' parameter to the 'screenshot' command, displayed when the user
# asks for help on what it does.
screenshotDPIManual=The number of dots per inch in the screenshot
# LOCALIZATION NOTE (screenshotFullscreenDesc) A very short string to describe
# the 'fullscreen' parameter to the 'screenshot' command, which is displayed in
# a dialog when the user is using this command.

View File

@ -4,6 +4,9 @@
# 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/.
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Web Apps')
EXTRA_PP_JS_MODULES += [
'NativeApp.jsm',
'WebappOSUtils.jsm',

View File

@ -586,3 +586,7 @@ AlertsService.init();
SimpleTest.registerCleanupFunction(() => {
AlertsService.restore();
});
function prepareEnv(cb) {
SpecialPowers.pushPrefEnv({"set":[["dom.mozApps.debug", true]]}, cb);
}

View File

@ -125,10 +125,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -161,10 +161,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -147,10 +147,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -106,10 +106,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -147,10 +147,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -93,10 +93,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -93,10 +93,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -135,10 +135,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -110,10 +110,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -116,10 +116,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -148,10 +148,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

View File

@ -164,10 +164,10 @@ let runTest = Task.async(function*() {
SimpleTest.finish();
});
runTest().catch((e) => {
prepareEnv(() => runTest().catch((e) => {
ok(false, "Error during test: " + e);
SimpleTest.finish();
});
}));
]]>
</script>

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