From 81e9f28cfcf6098150ac39f6d7b8fd099a48e35c Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:29:55 +0200 Subject: [PATCH 001/116] Bug 1422365 - Introduce nsIClearDataService - part 1 - IDL, r=johannh, r=mak --- browser/installer/package-manifest.in | 3 + mobile/android/installer/package-manifest.in | 3 + .../components/cleardata/ClearDataService.js | 33 ++++ .../cleardata/ClearDataService.manifest | 2 + toolkit/components/cleardata/moz.build | 25 +++ .../cleardata/nsIClearDataService.idl | 158 ++++++++++++++++++ toolkit/components/moz.build | 1 + 7 files changed, 225 insertions(+) create mode 100644 toolkit/components/cleardata/ClearDataService.js create mode 100644 toolkit/components/cleardata/ClearDataService.manifest create mode 100644 toolkit/components/cleardata/moz.build create mode 100644 toolkit/components/cleardata/nsIClearDataService.idl diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index d5fbc0ba6758..534463cafe02 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -324,6 +324,9 @@ @RESPATH@/components/SlowScriptDebug.manifest @RESPATH@/components/SlowScriptDebug.js +@RESPATH@/components/ClearDataService.manifest +@RESPATH@/components/ClearDataService.js + #ifdef MOZ_WEBRTC @RESPATH@/components/PeerConnection.js @RESPATH@/components/PeerConnection.manifest diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index c5863b4c8b3c..199c56b6fe7a 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -158,6 +158,9 @@ #endif #endif +@RESPATH@/components/ClearDataService.manifest +@RESPATH@/components/ClearDataService.js + @BINPATH@/components/nsUpdateTimerManager.manifest @BINPATH@/components/nsUpdateTimerManager.js diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js new file mode 100644 index 000000000000..c6b962cf38a3 --- /dev/null +++ b/toolkit/components/cleardata/ClearDataService.js @@ -0,0 +1,33 @@ +/* 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"; + +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this); + +this.ClearDataService = function() {}; + +ClearDataService.prototype = Object.freeze({ + classID: Components.ID("{0c06583d-7dd8-4293-b1a5-912205f779aa}"), + QueryInterface: ChromeUtils.generateQI([Ci.nsIClearDataService]), + _xpcom_factory: XPCOMUtils.generateSingletonFactory(ClearDataService), + + deleteDataFromHost(aHost, aIsUserRequest, aFlags, aCallback) { + // TODO + }, + + deleteDataFromPrincipal(aPrincipal, aIsUserRequest, aFlags, aCallback) { + // TODO + }, + + deleteDataInTimeRange(aFrom, aTo, aIsUserRequest, aFlags, aCallback) { + // TODO + }, + + deleteData(aFlags, aCallback) { + // TODO + }, +}); + +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ClearDataService]); diff --git a/toolkit/components/cleardata/ClearDataService.manifest b/toolkit/components/cleardata/ClearDataService.manifest new file mode 100644 index 000000000000..14d41349eb85 --- /dev/null +++ b/toolkit/components/cleardata/ClearDataService.manifest @@ -0,0 +1,2 @@ +component {0c06583d-7dd8-4293-b1a5-912205f779aa} ClearDataService.js +contract @mozilla.org/clear-data-service;1 {0c06583d-7dd8-4293-b1a5-912205f779aa} diff --git a/toolkit/components/cleardata/moz.build b/toolkit/components/cleardata/moz.build new file mode 100644 index 000000000000..ffa7e1cac63f --- /dev/null +++ b/toolkit/components/cleardata/moz.build @@ -0,0 +1,25 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +XPIDL_SOURCES += [ + 'nsIClearDataService.idl', +] + +XPIDL_MODULE = 'toolkit_cleardata' + +EXTRA_COMPONENTS += [ + 'ClearDataService.js', + 'ClearDataService.manifest', +] + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] + +include('/ipc/chromium/chromium-config.mozbuild') + +with Files('**'): + BUG_COMPONENT = ('Toolkit', 'Data Sanitization') + +FINAL_LIBRARY = 'xul' diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl new file mode 100644 index 000000000000..c655a71fb2d2 --- /dev/null +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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 nsIPrincipal; +interface nsIClearDataCallback; + +/** + * nsIClearDataService + * + * Provides methods for cleaning data from a nsIPrincipal and/or from a time + * range. + */ +[scriptable, uuid(6ef3ef16-a502-4576-9fb4-919f1c40bf61)] +interface nsIClearDataService : nsISupports +{ + /** + * Delete data owned by a host. For instance: mozilla.org. Data from any + * possible originAttributes will be deleted. + * @param aHost the host to be used. + * @param aIsUserRequest true if this request comes from a user interaction. + * This information is important because if true, it's probably better + * to remove more than less, for privacy reason. If false (e.g. + * Clear-Site-Data header), we don't want to delete more than what is + * strictly required. + * @param aFlags List of flags. See below the accepted values. + * @param aCallback this callback will be executed when the operation is + * completed. + */ + void deleteDataFromHost(in AUTF8String aHost, + in bool aIsUserRequest, + in uint32_t aFlags, + in nsIClearDataCallback aCallback); + + /** + * Delete data owned by a principal. + * @param aPrincipal the nsIPrincipal to be used. + * @param aIsUserRequest true if this request comes from a user interaction. + * This information is important because if true, it's probably better + * to remove more than less, for privacy reason. If false (e.g. + * Clear-Site-Data header), we don't want to delete more than what is + * strictly required. + * @param aFlags List of flags. See below the accepted values. + * @param aCallback ths callback will be executed when the operation is + * completed. + */ + void deleteDataFromPrincipal(in nsIPrincipal aPrincipal, + in bool aIsUserRequest, + in uint32_t aFlags, + in nsIClearDataCallback aCallback); + + /** + * Delete all data in a time range. Limit excluded. + * @param aFrom microseconds from the epoch + * @param aTo microseconds from the epoch + * @param aIsUserRequest true if this request comes from a user interaction. + * This information is important because if true, it's probably better + * to remove more than less, for privacy reason. If false (e.g. + * Clear-Site-Data header), we don't want to delete more than what is + * strictly required. + * @param aFlags List of flags. See below the accepted values. + * @param aCallback ths callback will be executed when the operation is + * completed. + */ + void deleteDataInTimeRange(in PRTime aFrom, in PRTime aTo, + in bool aIsUserRequest, + in uint32_t aFlags, + in nsIClearDataCallback aCallback); + + /** + * Delete all data from any host, in any time range. + * @param aFlags List of flags. See below the accepted values. + * @param aCallback ths callback will be executed when the operation is + * completed. + */ + void deleteData(in uint32_t aFlags, + in nsIClearDataCallback aCallback); + + /************************************************************************** + * Listed below are the various flags which may be or'd together. + */ + + /** + * Delete cookies. + */ + const uint32_t CLEAR_COOKIES = 1 << 0; + + /** + * Network Cache. + */ + const uint32_t CLEAR_NETWORK_CACHE = 1 << 1; + + /** + * Image cache. + */ + const uint32_t CLEAR_IMAGE_CACHE = 1 << 2; + + /* TODO + const uint32_t CLEAR_EME = 1 << 3; + const uint32_t CLEAR_PLUGIN_DATA = 1 << 4; + const uint32_t CLEAR_DOWNLOADS = 1 << 5; + const uint32_t CLEAR_PASSWORDS = 1 << 6; + const uint32_t CLEAR_PERMISSIONS = 1 << 7; + const uint32_t CLEAR_DOM_QUOTA = 1 << 8; + const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; + const uint32_t CLEAR_PREDICTOR_CACHE = 1 << 10; + const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 11; + const uint32_t CLEAR_HSTS = 1 << 12; + const uint32_t CLEAR_HPKP = 1 << 13; + const uint32_t CLEAR_HISTORY = 1 << 14; + const uint32_t CLEAR_SESSION_HISTORY = 1 << 15; + const uint32_t CLEAR_FORMDATA = 1 << 16; + const uint32_t CLEAR_AUTH_TOKENS = 1 << 17; + const uint32_t CLEAR_LOGINS = 1 << 18; + */ + + /** + * Use this value to delete all the data. + */ + const uint32_t CLEAR_ALL = 0xFFFF; + + /************************************************************************** + * The following flags are helpers: they combine some of the previous flags + * in a more convenient way. + */ + + /** + * Delete all the possible caches. + * TODO: add CLEAR_PREDICTOR_CACHE ? + */ + const uint32_t CLEAR_ALL_CACHES = CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE; + + /* + const uint32_t CLEAR_DOM_STORAGES = CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; + */ + + /* + const uint32_t CLEAR_BROWSER_DATA = CLEAR_DOWNLOADS | CLEAR_PASSWORDS | CLEAR_PERMISSIONS | CLEAR_CONTENT_PREFERENCES | CLEAR_HISTORY | CLEAR_LOGINS; + */ +}; + +/** + * This is a companion interface for + * nsIClearDataService::deleteDataFromPrincipal(). + */ +[function, scriptable, uuid(e225517b-24c5-498a-b9fb-9993e341a398)] +interface nsIClearDataCallback : nsISupports +{ + /** + * Called to indicate that the data cleaning is completed. + * @param aFailedFlags this value contains the flags that failed during the + * cleanup. If nothing failed, aFailedFlags will be 0. + */ + void onDataDeleted(in uint32_t aFailedFlags); +}; diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index df2ee14929f4..f2ed2343e440 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -21,6 +21,7 @@ DIRS += [ 'asyncshutdown', 'backgroundhangmonitor', 'browser', + 'cleardata', 'cloudstorage', 'commandlines', 'contentprefs', From f42b9d4e33a4ad1454d1ce94d7aa71d532223a0e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:29:59 +0200 Subject: [PATCH 002/116] Bug 1422365 - Introduce nsIClearDataService - part 2 - cookies/network cache/image cache, r=johannh --- browser/modules/Sanitizer.jsm | 72 ++----- .../components/cleardata/ClearDataService.js | 175 +++++++++++++++++- .../cleardata/tests/unit/.eslintrc.js | 7 + .../cleardata/tests/unit/test_basic.js | 22 +++ .../cleardata/tests/unit/test_cookies.js | 104 +++++++++++ .../cleardata/tests/unit/xpcshell.ini | 5 + toolkit/forgetaboutsite/ForgetAboutSite.jsm | 35 +--- toolkit/modules/Services.jsm | 1 + 8 files changed, 332 insertions(+), 89 deletions(-) create mode 100644 toolkit/components/cleardata/tests/unit/.eslintrc.js create mode 100644 toolkit/components/cleardata/tests/unit/test_basic.js create mode 100644 toolkit/components/cleardata/tests/unit/test_cookies.js create mode 100644 toolkit/components/cleardata/tests/unit/xpcshell.ini diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 6fd30f708835..17fca3c31c51 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -34,12 +34,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager", // Used as unique id for pending sanitizations. var gPendingSanitizationSerial = 0; -/** - * A number of iterations after which to yield time back - * to the system. - */ -const YIELD_PERIOD = 10; - /** * Cookie lifetime policy is currently used to cleanup on shutdown other * components such as QuotaManager, localStorage, ServiceWorkers. @@ -322,69 +316,22 @@ var Sanitizer = { items: { cache: { async clear(range) { - let seenException; let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_CACHE", refObj); - - try { - // Cache doesn't consult timespan, nor does it have the - // facility for timespan-based eviction. Wipe it. - Services.cache2.clear(); - } catch (ex) { - seenException = ex; - } - - try { - let imageCache = Cc["@mozilla.org/image/tools;1"] - .getService(Ci.imgITools) - .getImgCacheForDocument(null); - imageCache.clearCache(false); // true=chrome, false=content - } catch (ex) { - seenException = ex; - } - + await clearData(range, Ci.nsIClearDataService.CLEAR_ALL_CACHES); TelemetryStopwatch.finish("FX_SANITIZE_CACHE", refObj); - if (seenException) { - throw seenException; - } } }, cookies: { async clear(range) { let seenException; - let yieldCounter = 0; let refObj = {}; // Clear cookies. TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2", refObj); - try { - if (range) { - // Iterate through the cookies and delete any created after our cutoff. - let cookiesEnum = Services.cookies.enumerator; - while (cookiesEnum.hasMoreElements()) { - let cookie = cookiesEnum.getNext().QueryInterface(Ci.nsICookie2); - - if (cookie.creationTime > range[0]) { - // This cookie was created after our cutoff, clear it - Services.cookies.remove(cookie.host, cookie.name, cookie.path, - false, cookie.originAttributes); - - if (++yieldCounter % YIELD_PERIOD == 0) { - await new Promise(resolve => setTimeout(resolve, 0)); // Don't block the main thread too long - } - } - } - } else { - // Remove everything - Services.cookies.removeAll(); - await new Promise(resolve => setTimeout(resolve, 0)); // Don't block the main thread too long - } - } catch (ex) { - seenException = ex; - } finally { - TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2", refObj); - } + await clearData(range, Ci.nsIClearDataService.CLEAR_COOKIES); + TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2", refObj); // Clear deviceIds. Done asynchronously (returns before complete). try { @@ -1155,3 +1102,16 @@ function safeGetPendingSanitizations() { return []; } } + +async function clearData(range, flags) { + if (range) { + await new Promise(resolve => { + Services.clearData.deleteDataInTimeRange(range[0], range[1], true /* user request */, + flags, resolve); + }); + } else { + await new Promise(resolve => { + Services.clearData.deleteData(flags, resolve); + }); + } +} diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index c6b962cf38a3..7c3fb45d3eea 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -4,7 +4,102 @@ "use strict"; -ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this); +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.import("resource://gre/modules/Timer.jsm"); + +// A Cleaner is an object with 3 methods. These methods must return a Promise +// object. Here a description of these methods: +// * deleteAll() - this method _must_ exist. When called, it deletes all the +// data owned by the cleaner. +// * deleteByHost() - this method is implemented only if the cleaner knows +// how to delete data by host + originAttributes pattern. If +// not implemented, deleteAll() will be used as fallback. +// *deleteByRange() - this method is implemented only if the cleaner knows how +// to delete data by time range. It receives 2 time range +// parameters: aFrom/aTo. If not implemented, deleteAll() is +// used as fallback. + +const CookieCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise(aResolve => { + Services.cookies.removeCookiesWithOriginAttributes(JSON.stringify(aOriginAttributes), + aHost); + aResolve(); + }); + }, + + deleteByRange(aFrom, aTo) { + let enumerator = Services.cookies.enumerator; + return this._deleteInternal(enumerator, aCookie => aCookie.creationTime > aFrom); + }, + + deleteAll() { + return new Promise(aResolve => { + Services.cookies.removeAll(); + aResolve(); + }); + }, + + _deleteInternal(aEnumerator, aCb) { + // A number of iterations after which to yield time back to the system. + const YIELD_PERIOD = 10; + + return new Promise((aResolve, aReject) => { + let count = 0; + while (aEnumerator.hasMoreElements()) { + let cookie = aEnumerator.getNext().QueryInterface(Ci.nsICookie2); + if (aCb(cookie)) { + Services.cookies.remove(cookie.host, cookie.name, cookie.path, + false, cookie.originAttributes); + // We don't want to block the main-thread. + if (++count % YIELD_PERIOD == 0) { + setTimeout(() => { + this._deleteInternal(aEnumerator, aCb).then(aResolve, aReject); + }, 0); + return; + } + } + } + + aResolve(); + }); + }, + +}; + +const NetworkCacheCleaner = { + deleteAll() { + return new Promise(aResolve => { + Services.cache2.clear(); + aResolve(); + }); + }, +}; + +const ImageCacheCleaner = { + deleteAll() { + return new Promise(aResolve => { + let imageCache = Cc["@mozilla.org/image/tools;1"] + .getService(Ci.imgITools) + .getImgCacheForDocument(null); + imageCache.clearCache(false); // true=chrome, false=content + aResolve(); + }); + }, +}; + +// Here the map of Flags-Cleaner. +const FLAGS_MAP = [ + { flag: Ci.nsIClearDataService.CLEAR_COOKIES, + cleaner: CookieCleaner }, + + { flag: Ci.nsIClearDataService.CLEAR_NETWORK_CACHE, + cleaner: NetworkCacheCleaner }, + + { flag: Ci.nsIClearDataService.CLEAR_IMAGE_CACHE, + cleaner: ImageCacheCleaner, }, +]; this.ClearDataService = function() {}; @@ -14,19 +109,89 @@ ClearDataService.prototype = Object.freeze({ _xpcom_factory: XPCOMUtils.generateSingletonFactory(ClearDataService), deleteDataFromHost(aHost, aIsUserRequest, aFlags, aCallback) { - // TODO + if (!aHost || !aCallback) { + return Cr.NS_ERROR_INVALID_ARG; + } + + return this._deleteInternal(aFlags, aCallback, aCleaner => { + // Some of the 'Cleaners' do not support to delete by principal. Let's + // use deleteAll() as fallback. + if (aCleaner.deleteByHost) { + // A generic originAttributes dictionary. + return aCleaner.deleteByHost(aHost, {}); + } + // The user wants to delete data. Let's remove as much as we can. + if (aIsUserRequest) { + return aCleaner.deleteAll(); + } + // We don't want to delete more than what is strictly required. + return Promise.resolve(); + }); }, deleteDataFromPrincipal(aPrincipal, aIsUserRequest, aFlags, aCallback) { - // TODO + if (!aPrincipal || !aCallback) { + return Cr.NS_ERROR_INVALID_ARG; + } + + return this._deleteInternal(aFlags, aCallback, aCleaner => { + // Some of the 'Cleaners' do not support to delete by principal. Let's + // use deleteAll() as fallback. + if (aCleaner.deleteByHost) { + return aCleaner.deleteByHost(aPrincipal.URI.host, + aPrincipal.originAttributes); + } + // The user wants to delete data. Let's remove as much as we can. + if (aIsUserRequest) { + return aCleaner.deleteAll(); + } + // We don't want to delete more than what is strictly required. + return Promise.resolve(); + }); }, deleteDataInTimeRange(aFrom, aTo, aIsUserRequest, aFlags, aCallback) { - // TODO + if (aFrom > aTo || !aCallback) { + return Cr.NS_ERROR_INVALID_ARG; + } + + return this._deleteInternal(aFlags, aCallback, aCleaner => { + // Some of the 'Cleaners' do not support to delete by range. Let's use + // deleteAll() as fallback. + if (aCleaner.deleteByRange) { + return aCleaner.deleteByRange(aFrom, aTo); + } + // The user wants to delete data. Let's remove as much as we can. + if (aIsUserRequest) { + return aCleaner.deleteAll(); + } + // We don't want to delete more than what is strictly required. + return Promise.resolve(); + }); }, deleteData(aFlags, aCallback) { - // TODO + if (!aCallback) { + return Cr.NS_ERROR_INVALID_ARG; + } + + return this._deleteInternal(aFlags, aCallback, aCleaner => { + return aCleaner.deleteAll(); + }); + }, + + // This internal method uses aFlags against FLAGS_MAP in order to retrieve a + // list of 'Cleaners'. For each of them, the aHelper callback retrieves a + // promise object. All these promise objects are resolved before calling + // onDataDeleted. + _deleteInternal(aFlags, aCallback, aHelper) { + let resultFlags = 0; + let promises = FLAGS_MAP.filter(c => aFlags & c.flag).map(c => { + // Let's collect the failure in resultFlags. + return aHelper(c.cleaner).catch(() => { resultFlags |= c.flag; }); + }); + Promise.all(promises).then(() => { aCallback.onDataDeleted(resultFlags); }); + return Cr.NS_OK; }, }); diff --git a/toolkit/components/cleardata/tests/unit/.eslintrc.js b/toolkit/components/cleardata/tests/unit/.eslintrc.js new file mode 100644 index 000000000000..70fe35407782 --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/.eslintrc.js @@ -0,0 +1,7 @@ +"use strict"; + +module.exports = { + "extends": [ + "plugin:mozilla/xpcshell-test" + ] +}; diff --git a/toolkit/components/cleardata/tests/unit/test_basic.js b/toolkit/components/cleardata/tests/unit/test_basic.js new file mode 100644 index 000000000000..6f740f9190cb --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/test_basic.js @@ -0,0 +1,22 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Basic test for nsIClearDataService module. + */ + +"use strict"; + +add_task(async function test_basic() { + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + Assert.ok(!!service); + + await new Promise(aResolve => { + service.deleteData(Ci.nsIClearDataService.CLEAR_IMAGE_CACHE | + Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); +}); diff --git a/toolkit/components/cleardata/tests/unit/test_cookies.js b/toolkit/components/cleardata/tests/unit/test_cookies.js new file mode 100644 index 000000000000..83e16fc5140d --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/test_cookies.js @@ -0,0 +1,104 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests for cookies. + */ + +"use strict"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +add_task(async function test_all_cookies() { + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + Assert.ok(!!service); + + const expiry = Date.now() + 24 * 60 * 60; + Services.cookies.add("example.net", "path", "name", "value", true /* secure */, + true /* http only */, false /* session */, + expiry, {}); + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); + + await new Promise(aResolve => { + service.deleteData(Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); + + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0); +}); + +add_task(async function test_range_cookies() { + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + Assert.ok(!!service); + + const expiry = Date.now() + 24 * 60 * 60; + Services.cookies.add("example.net", "path", "name", "value", true /* secure */, + true /* http only */, false /* session */, + expiry, {}); + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); + + // The cookie is out of time range here. + let from = Date.now() + 60 * 60; + await new Promise(aResolve => { + service.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); + + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); + + // Now we delete all. + from = Date.now() - 60 * 60; + await new Promise(aResolve => { + service.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); + + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0); +}); + +add_task(async function test_principal_cookies() { + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + Assert.ok(!!service); + + const expiry = Date.now() + 24 * 60 * 60; + Services.cookies.add("example.net", "path", "name", "value", true /* secure */, + true /* http only */, false /* session */, + expiry, {}); + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); + + let uri = Services.io.newURI("http://example.com"); + let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); + await new Promise(aResolve => { + service.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); + + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); + + // Now we delete all. + uri = Services.io.newURI("http://example.net"); + principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); + await new Promise(aResolve => { + service.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Assert.equal(value, 0); + aResolve(); + }); + }); + + Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0); +}); diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.ini b/toolkit/components/cleardata/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..7a9faca5ceeb --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +support-files = + +[test_basic.js] +[test_cookies.js] diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 47a21609f79b..c09337f204a8 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -45,35 +45,14 @@ var ForgetAboutSite = { await PlacesUtils.history.removeByFilter({ host: "." + aDomain }); let promises = []; - // Cache - promises.push((async function() { - // NOTE: there is no way to clear just that domain, so we clear out - // everything) - Services.cache2.clear(); - })().catch(ex => { - throw new Error("Exception thrown while clearing the cache: " + ex); - })); - // Image Cache - promises.push((async function() { - let imageCache = Cc["@mozilla.org/image/tools;1"]. - getService(Ci.imgITools).getImgCacheForDocument(null); - imageCache.clearCache(false); // true=chrome, false=content - })().catch(ex => { - throw new Error("Exception thrown while clearing the image cache: " + ex); - })); - - // Cookies - // Need to maximize the number of cookies cleaned here - promises.push((async function() { - let enumerator = Services.cookies.getCookiesWithOriginAttributes(JSON.stringify({}), aDomain); - while (enumerator.hasMoreElements()) { - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie); - Services.cookies.remove(cookie.host, cookie.name, cookie.path, false, cookie.originAttributes); - } - })().catch(ex => { - throw new Error("Exception thrown while clearning cookies: " + ex); - })); + ["http://", "https://"].forEach(scheme => { + promises.push(new Promise(resolve => { + Services.clearData.deleteDataFromHost(aDomain, true /* user request */, + Ci.nsIClearDataService.CLEAR_ALL, + resolve); + })); + }); // EME promises.push((async function() { diff --git a/toolkit/modules/Services.jsm b/toolkit/modules/Services.jsm index 7247c9bb2a82..e7e12067e008 100644 --- a/toolkit/modules/Services.jsm +++ b/toolkit/modules/Services.jsm @@ -60,6 +60,7 @@ XPCOMUtils.defineLazyGetter(Services, "io", () => { var initTable = { appShell: ["@mozilla.org/appshell/appShellService;1", "nsIAppShellService"], cache2: ["@mozilla.org/netwerk/cache-storage-service;1", "nsICacheStorageService"], + clearData: ["@mozilla.org/clear-data-service;1", "nsIClearDataService"], cpmm: ["@mozilla.org/childprocessmessagemanager;1", "nsIMessageSender"], console: ["@mozilla.org/consoleservice;1", "nsIConsoleService"], cookies: ["@mozilla.org/cookiemanager;1", "nsICookieManager"], From 7a1184f9d69f2f3c889b271dab88150b4ac99bd3 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:29:59 +0200 Subject: [PATCH 003/116] Bug 1422365 - Introduce nsIClearDataService - part 3 - plugin data, r=johannh --- browser/modules/Sanitizer.jsm | 94 ++----------------- .../components/cleardata/ClearDataService.js | 85 +++++++++++++++++ .../cleardata/nsIClearDataService.idl | 8 +- .../cleardata/tests/unit/test_basic.js | 3 +- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 17 ---- 5 files changed, 99 insertions(+), 108 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 17fca3c31c51..0e4138d4c6e8 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -14,7 +14,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { FormHistory: "resource://gre/modules/FormHistory.jsm", Downloads: "resource://gre/modules/Downloads.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", - setTimeout: "resource://gre/modules/Timer.jsm", ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm", @@ -325,33 +324,18 @@ var Sanitizer = { cookies: { async clear(range) { - let seenException; let refObj = {}; - // Clear cookies. + // Clear cookies and plugin data. TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2", refObj); - await clearData(range, Ci.nsIClearDataService.CLEAR_COOKIES); + await clearData(range, Ci.nsIClearDataService.CLEAR_COOKIES | + Ci.nsIClearDataService.CLEAR_PLUGIN_DATA); TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2", refObj); // Clear deviceIds. Done asynchronously (returns before complete). - try { - let mediaMgr = Cc["@mozilla.org/mediaManagerService;1"] - .getService(Ci.nsIMediaManagerService); - mediaMgr.sanitizeDeviceIds(range && range[0]); - } catch (ex) { - seenException = ex; - } - - // Clear plugin data. - try { - await clearPluginData(range); - } catch (ex) { - seenException = ex; - } - - if (seenException) { - throw seenException; - } + let mediaMgr = Cc["@mozilla.org/mediaManagerService;1"] + .getService(Ci.nsIMediaManagerService); + mediaMgr.sanitizeDeviceIds(range && range[0]); }, }, @@ -772,7 +756,7 @@ var Sanitizer = { pluginData: { async clear(range) { - await clearPluginData(range); + await clearData(range, Ci.nsIClearDataService.CLEAR_PLUGIN_DATA); }, }, }, @@ -862,70 +846,6 @@ async function sanitizeInternal(items, aItemsToClear, progress, options = {}) { } } -async function clearPluginData(range) { - // Clear plugin data. - // As evidenced in bug 1253204, clearing plugin data can sometimes be - // very, very long, for mysterious reasons. Unfortunately, this is not - // something actionable by Mozilla, so crashing here serves no purpose. - // - // For this reason, instead of waiting for sanitization to always - // complete, we introduce a soft timeout. Once this timeout has - // elapsed, we proceed with the shutdown of Firefox. - let seenException; - - let promiseClearPluginData = async function() { - const FLAG_CLEAR_ALL = Ci.nsIPluginHost.FLAG_CLEAR_ALL; - let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); - - // Determine age range in seconds. (-1 means clear all.) We don't know - // that range[1] is actually now, so we compute age range based - // on the lower bound. If range results in a negative age, do nothing. - let age = range ? (Date.now() / 1000 - range[0] / 1000000) : -1; - if (!range || age >= 0) { - let tags = ph.getPluginTags(); - for (let tag of tags) { - try { - let rv = await new Promise(resolve => - ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, age, resolve) - ); - // If the plugin doesn't support clearing by age, clear everything. - if (rv == Cr.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) { - await new Promise(resolve => - ph.clearSiteData(tag, null, FLAG_CLEAR_ALL, -1, resolve) - ); - } - } catch (ex) { - // Ignore errors from plug-ins - } - } - } - }; - - try { - // We don't want to wait for this operation to complete... - promiseClearPluginData = promiseClearPluginData(range); - - // ... at least, not for more than 10 seconds. - await Promise.race([ - promiseClearPluginData, - new Promise(resolve => setTimeout(resolve, 10000 /* 10 seconds */)) - ]); - } catch (ex) { - seenException = ex; - } - - // Detach waiting for plugin data to be cleared. - promiseClearPluginData.catch(() => { - // If this exception is raised before the soft timeout, it - // will appear in `seenException`. Otherwise, it's too late - // to do anything about it. - }); - - if (seenException) { - throw seenException; - } -} - async function sanitizeOnShutdown(progress) { if (Sanitizer.shouldSanitizeOnShutdown) { // Need to sanitize upon shutdown diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 7c3fb45d3eea..165e7f081f8c 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -89,6 +89,88 @@ const ImageCacheCleaner = { }, }; +const PluginDataCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return this._deleteInternal((aPh, aTag) => { + return new Promise(aResolve => { + try { + aPh.clearSiteData(aTag, aHost, + Ci.nsIPluginHost.FLAG_CLEAR_ALL, + -1, aResolve); + } catch (e) { + // Ignore errors from the plugin, but resolve the promise + // We cannot check if something is a bailout or an error + aResolve(); + } + }); + }); + }, + + deleteByRange(aFrom, aTo) { + let age = Date.now() / 1000 - aFrom / 1000000; + + return this._deleteInternal((aPh, aTag) => { + return new Promise(aResolve => { + try { + aPh.clearSiteData(aTag, null, Ci.nsIPluginHost.FLAG_CLEAR_ALL, + age, aResolve); + } catch (e) { + aResolve(Cr.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED); + } + }).then(aRv => { + // If the plugin doesn't support clearing by age, clear everything. + if (aRv == Cr.NS_ERROR_PLUGIN_TIME_RANGE_NOT_SUPPORTED) { + return new Promise(aResolve => { + try { + aPh.clearSiteData(aTag, null, Ci.nsIPluginHost.FLAG_CLEAR_ALL, + -1, aResolve); + } catch (e) { + aResolve(); + } + }); + } + + return true; + }); + }); + }, + + deleteAll() { + return this._deleteInternal((aPh, aTag) => { + return new Promise(aResolve => { + try { + aPh.clearSiteData(aTag, null, Ci.nsIPluginHost.FLAG_CLEAR_ALL, -1, + aResolve); + } catch (e) { + aResolve(); + } + }); + }); + }, + + _deleteInternal(aCb) { + let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + + let promises = []; + let tags = ph.getPluginTags(); + for (let tag of tags) { + promises.push(aCb(ph, tag)); + } + + // As evidenced in bug 1253204, clearing plugin data can sometimes be + // very, very long, for mysterious reasons. Unfortunately, this is not + // something actionable by Mozilla, so crashing here serves no purpose. + // + // For this reason, instead of waiting for sanitization to always + // complete, we introduce a soft timeout. Once this timeout has + // elapsed, we proceed with the shutdown of Firefox. + return Promise.race([ + Promise.all(promises), + new Promise(aResolve => setTimeout(aResolve, 10000 /* 10 seconds */)) + ]); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -99,6 +181,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_IMAGE_CACHE, cleaner: ImageCacheCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_PLUGIN_DATA, + cleaner: PluginDataCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index c655a71fb2d2..23583e121a36 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -98,9 +98,13 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_IMAGE_CACHE = 1 << 2; + /** + * Data stored by external plugins. + */ + const uint32_t CLEAR_PLUGIN_DATA = 1 << 3; + /* TODO - const uint32_t CLEAR_EME = 1 << 3; - const uint32_t CLEAR_PLUGIN_DATA = 1 << 4; + const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_DOWNLOADS = 1 << 5; const uint32_t CLEAR_PASSWORDS = 1 << 6; const uint32_t CLEAR_PERMISSIONS = 1 << 7; diff --git a/toolkit/components/cleardata/tests/unit/test_basic.js b/toolkit/components/cleardata/tests/unit/test_basic.js index 6f740f9190cb..1c0db3661fe0 100644 --- a/toolkit/components/cleardata/tests/unit/test_basic.js +++ b/toolkit/components/cleardata/tests/unit/test_basic.js @@ -13,8 +13,7 @@ add_task(async function test_basic() { Assert.ok(!!service); await new Promise(aResolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_IMAGE_CACHE | - Ci.nsIClearDataService.CLEAR_COOKIES, value => { + service.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => { Assert.equal(value, 0); aResolve(); }); diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index c09337f204a8..d34aff7a689a 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -64,23 +64,6 @@ var ForgetAboutSite = { })); - // Plugin data - const phInterface = Ci.nsIPluginHost; - const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL; - let ph = Cc["@mozilla.org/plugin/host;1"].getService(phInterface); - let tags = ph.getPluginTags(); - for (let i = 0; i < tags.length; i++) { - promises.push(new Promise(resolve => { - try { - ph.clearSiteData(tags[i], aDomain, FLAG_CLEAR_ALL, -1, resolve); - } catch (e) { - // Ignore errors from the plugin, but resolve the promise - // We cannot check if something is a bailout or an error - resolve(); - } - })); - } - // Downloads promises.push((async function() { let list = await Downloads.getList(Downloads.ALL); From dfdb3c9d3056820408e8318ba8af406e246c61f2 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 004/116] Bug 1422365 - Introduce nsIClearDataService - part 4 - download, r=johannh --- browser/modules/Sanitizer.jsm | 19 +- .../components/cleardata/ClearDataService.js | 54 ++++++ .../cleardata/nsIClearDataService.idl | 6 +- .../components/cleardata/tests/unit/head.js | 6 + .../cleardata/tests/unit/test_downloads.js | 180 ++++++++++++++++++ .../cleardata/tests/unit/xpcshell.ini | 2 + toolkit/forgetaboutsite/ForgetAboutSite.jsm | 10 - 7 files changed, 249 insertions(+), 28 deletions(-) create mode 100644 toolkit/components/cleardata/tests/unit/head.js create mode 100644 toolkit/components/cleardata/tests/unit/test_downloads.js diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 0e4138d4c6e8..8ad522cebdc6 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -12,7 +12,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { AppConstants: "resource://gre/modules/AppConstants.jsm", PlacesUtils: "resource://gre/modules/PlacesUtils.jsm", FormHistory: "resource://gre/modules/FormHistory.jsm", - Downloads: "resource://gre/modules/Downloads.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", @@ -521,22 +520,8 @@ var Sanitizer = { async clear(range) { let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_DOWNLOADS", refObj); - try { - let filterByTime = null; - if (range) { - // Convert microseconds back to milliseconds for date comparisons. - let rangeBeginMs = range[0] / 1000; - let rangeEndMs = range[1] / 1000; - filterByTime = download => download.startTime >= rangeBeginMs && - download.startTime <= rangeEndMs; - } - - // Clear all completed/cancelled downloads - let list = await Downloads.getList(Downloads.ALL); - list.removeFinished(filterByTime); - } finally { - TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS", refObj); - } + await clearData(range, Ci.nsIClearDataService.CLEAR_DOWNLOADS); + TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS", refObj); } }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 165e7f081f8c..0d61a303d4fd 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -7,6 +7,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/Timer.jsm"); +ChromeUtils.import("resource://gre/modules/Downloads.jsm"); // A Cleaner is an object with 3 methods. These methods must return a Promise // object. Here a description of these methods: @@ -171,6 +172,32 @@ const PluginDataCleaner = { }, }; +const DownloadsCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return Downloads.getList(Downloads.ALL).then(aList => { + aList.removeFinished(aDownload => hasRootDomain( + Services.io.newURI(aDownload.source.url).host, aHost)); + }); + }, + + deleteByRange(aFrom, aTo) { + // Convert microseconds back to milliseconds for date comparisons. + let rangeBeginMs = aFrom / 1000; + let rangeEndMs = aTo / 1000; + + return Downloads.getList(Downloads.ALL).then(aList => { + aList.removeFinished(aDownload => aDownload.startTime >= rangeBeginMs && + aDownload.startTime <= rangeEndMs); + }); + }, + + deleteAll() { + return Downloads.getList(Downloads.ALL).then(aList => { + aList.removeFinished(null); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -184,6 +211,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_PLUGIN_DATA, cleaner: PluginDataCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_DOWNLOADS, + cleaner: DownloadsCleaner, }, ]; this.ClearDataService = function() {}; @@ -281,3 +311,27 @@ ClearDataService.prototype = Object.freeze({ }); this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ClearDataService]); + +/** + * Returns true if the string passed in is part of the root domain of the + * current string. For example, if this is "www.mozilla.org", and we pass in + * "mozilla.org", this will return true. It would return false the other way + * around. + */ +function hasRootDomain(str, aDomain) { + let index = str.indexOf(aDomain); + // If aDomain is not found, we know we do not have it as a root domain. + if (index == -1) + return false; + + // If the strings are the same, we obviously have a match. + if (str == aDomain) + return true; + + // Otherwise, we have aDomain as our root domain iff the index of aDomain is + // aDomain.length subtracted from our length and (since we do not have an + // exact match) the character before the index is a dot or slash. + let prevChar = str[index - 1]; + return (index == (str.length - aDomain.length)) && + (prevChar == "." || prevChar == "/"); +} diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 23583e121a36..ffb9690a7a15 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -103,9 +103,13 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_PLUGIN_DATA = 1 << 3; + /** + * Completed downloads. + */ + const uint32_t CLEAR_DOWNLOADS = 1 << 4; + /* TODO const uint32_t CLEAR_EME = 1 << 4; - const uint32_t CLEAR_DOWNLOADS = 1 << 5; const uint32_t CLEAR_PASSWORDS = 1 << 6; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_DOM_QUOTA = 1 << 8; diff --git a/toolkit/components/cleardata/tests/unit/head.js b/toolkit/components/cleardata/tests/unit/head.js new file mode 100644 index 000000000000..ebb3af423885 --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/head.js @@ -0,0 +1,6 @@ +"use strict"; + +function run_test() { + do_get_profile(); + run_next_test(); +} diff --git a/toolkit/components/cleardata/tests/unit/test_downloads.js b/toolkit/components/cleardata/tests/unit/test_downloads.js new file mode 100644 index 000000000000..52a8b35c8858 --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/test_downloads.js @@ -0,0 +1,180 @@ +/** + * Tests for downloads. + */ + +"use strict"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.import("resource://gre/modules/Downloads.jsm"); +ChromeUtils.import("resource://testing-common/FileTestUtils.jsm"); + +const TEST_TARGET_FILE_NAME = "test-download.txt"; +let fileURL; +let downloadList; + +function createFileURL() { + if (!fileURL) { + const file = Services.dirsvc.get("TmpD", Ci.nsIFile); + file.append("foo.txt"); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + fileURL = Services.io.newFileURI(file); + } + + return fileURL; +} + +async function createDownloadList() { + if (!downloadList) { + Downloads._promiseListsInitialized = null; + Downloads._lists = {}; + Downloads._summaries = {}; + + downloadList = await Downloads.getList(Downloads.ALL); + } + + return downloadList; +} + +add_task(async function test_all_downloads() { + const url = createFileURL(); + + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + Assert.ok(!!service); + + const list = await createDownloadList(); + + // First download. + let download = await Downloads.createDownload({ + source: { url: url.spec, isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + }); + Assert.ok(!!download); + list.add(download); + + // Second download. + download = await Downloads.createDownload({ + source: { url: url.spec, isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + }); + await download.start(); + Assert.ok(!!download); + list.add(download); + + let items = await list.getAll(); + Assert.equal(items.length, 2); + + await new Promise(resolve => { + service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + items = await list.getAll(); + + // We don't remove the active downloads. + Assert.equal(items.length, 1); + + await download.cancel(); + + await new Promise(resolve => { + service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + items = await list.getAll(); + Assert.equal(items.length, 0); +}); + +add_task(async function test_range_downloads() { + const url = createFileURL(); + + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + + Assert.ok(!!service); + + const list = await createDownloadList(); + + let download = await Downloads.createDownload({ + source: { url: url.spec, isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + }); + Assert.ok(!!download); + list.add(download); + + // Start + cancel. I need to have a startTime value. + await download.start(); + await download.cancel(); + + let items = await list.getAll(); + Assert.equal(items.length, 1); + + await new Promise(resolve => { + service.deleteDataInTimeRange(download.startTime.getTime() * 1000, + download.startTime.getTime() * 1000, + true /* user request */, + Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + items = await list.getAll(); + Assert.equal(items.length, 0); +}); + +add_task(async function test_principal_downloads() { + const service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + + Assert.ok(!!service); + + const list = await createDownloadList(); + + let download = await Downloads.createDownload({ + source: { url: "http://example.net", isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + }); + Assert.ok(!!download); + list.add(download); + + download = await Downloads.createDownload({ + source: { url: "http://example.com", isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + }); + Assert.ok(!!download); + list.add(download); + + let items = await list.getAll(); + Assert.equal(items.length, 2); + + let uri = Services.io.newURI("http://example.com"); + let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); + + await new Promise(resolve => { + service.deleteDataFromPrincipal(principal, + true /* user request */, + Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + items = await list.getAll(); + Assert.equal(items.length, 1); + + await new Promise(resolve => { + service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + items = await list.getAll(); + Assert.equal(items.length, 0); +}); diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.ini b/toolkit/components/cleardata/tests/unit/xpcshell.ini index 7a9faca5ceeb..4cf81aa020b9 100644 --- a/toolkit/components/cleardata/tests/unit/xpcshell.ini +++ b/toolkit/components/cleardata/tests/unit/xpcshell.ini @@ -1,5 +1,7 @@ [DEFAULT] +head = head.js support-files = [test_basic.js] [test_cookies.js] +[test_downloads.js] diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index d34aff7a689a..96ab4ab9005f 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -63,16 +63,6 @@ var ForgetAboutSite = { throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); })); - - // Downloads - promises.push((async function() { - let list = await Downloads.getList(Downloads.ALL); - list.removeFinished(download => hasRootDomain( - NetUtil.newURI(download.source.url).host, aDomain)); - })().catch(ex => { - throw new Error("Exception in clearing Downloads: " + ex); - })); - // Passwords promises.push((async function() { // Clear all passwords for domain From d50201f1067ca1fff6befffbe9ce0bf2a6cbfe2c Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 005/116] Bug 1422365 - Introduce nsIClearDataService - part 5 - passwords, r=johannh --- .../components/cleardata/ClearDataService.js | 34 ++++++++ .../cleardata/nsIClearDataService.idl | 6 +- .../cleardata/tests/unit/test_passwords.js | 78 +++++++++++++++++++ .../cleardata/tests/unit/xpcshell.ini | 1 + toolkit/forgetaboutsite/ForgetAboutSite.jsm | 15 ---- 5 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 toolkit/components/cleardata/tests/unit/test_passwords.js diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 0d61a303d4fd..5b6de130c3f6 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -198,6 +198,37 @@ const DownloadsCleaner = { }, }; +const PasswordsCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return this._deleteInternal(aLogin => hasRootDomain(aLogin.hostname, aHost)); + }, + + deleteAll() { + return this._deleteInternal(() => true); + }, + + _deleteInternal(aCb) { + return new Promise(aResolve => { + try { + let logins = Services.logins.getAllLogins(); + for (let login of logins) { + if (aCb(login)) { + Services.logins.removeLogin(login); + } + } + } catch (ex) { + // XXXehsan: is there a better way to do this rather than this + // hacky comparison? + if (!ex.message.includes("User canceled Master Password entry")) { + throw new Error("Exception occured in clearing passwords :" + ex); + } + } + + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -214,6 +245,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_DOWNLOADS, cleaner: DownloadsCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_PASSWORDS, + cleaner: PasswordsCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index ffb9690a7a15..a988df18f08c 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -108,9 +108,13 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_DOWNLOADS = 1 << 4; + /** + * Stored passwords. + */ + const uint32_t CLEAR_PASSWORDS = 1 << 5; + /* TODO const uint32_t CLEAR_EME = 1 << 4; - const uint32_t CLEAR_PASSWORDS = 1 << 6; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_DOM_QUOTA = 1 << 8; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; diff --git a/toolkit/components/cleardata/tests/unit/test_passwords.js b/toolkit/components/cleardata/tests/unit/test_passwords.js new file mode 100644 index 000000000000..e47bae46014c --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/test_passwords.js @@ -0,0 +1,78 @@ +/** + * Tests for passwords. + */ + +"use strict"; + +const URL = "http://example.com"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); +ChromeUtils.import("resource://testing-common/LoginTestUtils.jsm"); + +add_task(async function test_principal_downloads() { + // Store the strings "user" and "pass" using similarly looking glyphs. + let loginInfo = LoginTestUtils.testData.formLogin({ + hostname: URL, + formSubmitURL: URL, + username: "admin", + password: "12345678", + usernameField: "field_username", + passwordField: "field_password", + }); + Services.logins.addLogin(loginInfo); + + Assert.equal(countLogins(URL), 1); + + let uri = Services.io.newURI(URL); + let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); + + await new Promise(resolve => { + Services.clearData.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_PASSWORDS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + Assert.equal(countLogins(URL), 0); + + LoginTestUtils.clearData(); +}); + +add_task(async function test_all() { + // Store the strings "user" and "pass" using similarly looking glyphs. + let loginInfo = LoginTestUtils.testData.formLogin({ + hostname: URL, + formSubmitURL: URL, + username: "admin", + password: "12345678", + usernameField: "field_username", + passwordField: "field_password", + }); + Services.logins.addLogin(loginInfo); + + Assert.equal(countLogins(URL), 1); + + await new Promise(resolve => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_PASSWORDS, value => { + Assert.equal(value, 0); + resolve(); + }); + }); + + Assert.equal(countLogins(URL), 0); + + LoginTestUtils.clearData(); +}); + +function countLogins(host) { + let count = 0; + const logins = Services.logins.getAllLogins(); + for (const login of logins) { + if (login.hostname == host) { + ++count; + } + } + + return count; +} diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.ini b/toolkit/components/cleardata/tests/unit/xpcshell.ini index 4cf81aa020b9..9bdae7c8f86f 100644 --- a/toolkit/components/cleardata/tests/unit/xpcshell.ini +++ b/toolkit/components/cleardata/tests/unit/xpcshell.ini @@ -5,3 +5,4 @@ support-files = [test_basic.js] [test_cookies.js] [test_downloads.js] +[test_passwords.js] diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 96ab4ab9005f..0c079d11f13d 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -63,21 +63,6 @@ var ForgetAboutSite = { throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); })); - // Passwords - promises.push((async function() { - // Clear all passwords for domain - let logins = Services.logins.getAllLogins(); - for (let i = 0; i < logins.length; i++) - if (hasRootDomain(logins[i].hostname, aDomain)) - Services.logins.removeLogin(logins[i]); - })().catch(ex => { - // XXXehsan: is there a better way to do this rather than this - // hacky comparison? - if (!ex.message.includes("User canceled Master Password entry")) { - throw new Error("Exception occured in clearing passwords :" + ex); - } - })); - // Permissions // Enumerate all of the permissions, and if one matches, remove it let enumerator = Services.perms.enumerator; From 1a54d00d856e9485f7b25c34f406a937d66ea327 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 006/116] Bug 1422365 - Introduce nsIClearDataService - part 6 - Media devices, r=johannh --- browser/modules/Sanitizer.jsm | 10 ++------ .../components/cleardata/ClearDataService.js | 23 +++++++++++++++++++ .../cleardata/nsIClearDataService.idl | 5 ++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 8ad522cebdc6..84781503af2e 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -324,17 +324,11 @@ var Sanitizer = { cookies: { async clear(range) { let refObj = {}; - - // Clear cookies and plugin data. TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2", refObj); await clearData(range, Ci.nsIClearDataService.CLEAR_COOKIES | - Ci.nsIClearDataService.CLEAR_PLUGIN_DATA); + Ci.nsIClearDataService.CLEAR_PLUGIN_DATA | + Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES); TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2", refObj); - - // Clear deviceIds. Done asynchronously (returns before complete). - let mediaMgr = Cc["@mozilla.org/mediaManagerService;1"] - .getService(Ci.nsIMediaManagerService); - mediaMgr.sanitizeDeviceIds(range && range[0]); }, }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 5b6de130c3f6..25a8250cc0d3 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -229,6 +229,26 @@ const PasswordsCleaner = { }, }; +const MediaDevicesCleaner = { + deleteByRange(aFrom, aTo) { + return new Promise(aResolve => { + let mediaMgr = Cc["@mozilla.org/mediaManagerService;1"] + .getService(Ci.nsIMediaManagerService); + mediaMgr.sanitizeDeviceIds(aFrom); + aResolve(); + }); + }, + + deleteAll() { + return new Promise(aResolve => { + let mediaMgr = Cc["@mozilla.org/mediaManagerService;1"] + .getService(Ci.nsIMediaManagerService); + mediaMgr.sanitizeDeviceIds(null); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -248,6 +268,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_PASSWORDS, cleaner: PasswordsCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES, + cleaner: MediaDevicesCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index a988df18f08c..9365e5690e4e 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -113,6 +113,11 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_PASSWORDS = 1 << 5; + /** + * Media devices. + */ + const uint32_t CLEAR_MEDIA_DEVICES = 1 << 6; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; From d7ef003a02d5f7b39982d104840a9713ea0f4715 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 007/116] Bug 1422365 - Introduce nsIClearDataService - part 7 - appCache, r=johannh --- browser/modules/Sanitizer.jsm | 4 +--- .../components/cleardata/ClearDataService.js | 19 +++++++++++++++++-- .../cleardata/nsIClearDataService.idl | 13 ++++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 84781503af2e..992856606733 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -14,7 +14,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { FormHistory: "resource://gre/modules/FormHistory.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", - OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm", }); @@ -334,8 +333,7 @@ var Sanitizer = { offlineApps: { async clear(range) { - // AppCache: this doesn't wait for the cleanup to be complete. - OfflineAppCacheHelper.clear(); + await clearData(range, Ci.nsIClearDataService.CLEAR_DOM_STORAGES); if (range) { let principals = sas.getActiveOrigins(range[0], range[1]) diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 25a8250cc0d3..169747922e46 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -6,8 +6,12 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/Services.jsm"); -ChromeUtils.import("resource://gre/modules/Timer.jsm"); -ChromeUtils.import("resource://gre/modules/Downloads.jsm"); + +XPCOMUtils.defineLazyModuleGetters(this, { + setTimeout: "resource://gre/modules/Timer.jsm", + Downloads: "resource://gre/modules/Downloads.jsm", + OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", +}); // A Cleaner is an object with 3 methods. These methods must return a Promise // object. Here a description of these methods: @@ -249,6 +253,14 @@ const MediaDevicesCleaner = { }, }; +const AppCacheCleaner = { + deleteAll() { + // AppCache: this doesn't wait for the cleanup to be complete. + OfflineAppCacheHelper.clear(); + return Promise.resolve(); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -271,6 +283,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_MEDIA_DEVICES, cleaner: MediaDevicesCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_APPCACHE, + cleaner: AppCacheCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 9365e5690e4e..d49edfaab331 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -118,6 +118,11 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_MEDIA_DEVICES = 1 << 6; + /** + * AppCache. + */ + const uint32_t CLEAR_APPCACHE = 1 << 7; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; @@ -150,9 +155,11 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_ALL_CACHES = CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE; - /* - const uint32_t CLEAR_DOM_STORAGES = CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; - */ + /** + * Delete all DOM storages + * TODO: add CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; + */ + const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE; /* const uint32_t CLEAR_BROWSER_DATA = CLEAR_DOWNLOADS | CLEAR_PASSWORDS | CLEAR_PERMISSIONS | CLEAR_CONTENT_PREFERENCES | CLEAR_HISTORY | CLEAR_LOGINS; From eea87c177b799dca320089001ba47fa63c3c31c7 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 008/116] Bug 1422365 - Introduce nsIClearDataService - part 8 - DOM Quota, r=johannh --- .../sessionstore/test/browser_464199.js | 3 +- browser/modules/Sanitizer.jsm | 82 +---------- .../components/cleardata/ClearDataService.js | 139 +++++++++++++++++- .../cleardata/nsIClearDataService.idl | 10 +- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 26 ---- 5 files changed, 152 insertions(+), 108 deletions(-) diff --git a/browser/components/sessionstore/test/browser_464199.js b/browser/components/sessionstore/test/browser_464199.js index 6af1496f95ac..1c4308f1fd50 100644 --- a/browser/components/sessionstore/test/browser_464199.js +++ b/browser/components/sessionstore/test/browser_464199.js @@ -68,8 +68,9 @@ add_task(async function() { is(countByTitle(closedTabs, REMEMBER), remember_count, "Everything is set up."); + let promise = promiseClearHistory(); await ForgetAboutSite.removeDataFromDomain("example.net"); - await promiseClearHistory(); + await promise; closedTabs = JSON.parse(ss.getClosedTabData(newWin)); is(closedTabs.length, remember_count, "The correct amout of tabs was removed"); diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 992856606733..ad4979411c73 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -13,13 +13,9 @@ XPCOMUtils.defineLazyModuleGetters(this, { PlacesUtils: "resource://gre/modules/PlacesUtils.jsm", FormHistory: "resource://gre/modules/FormHistory.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", - ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm", }); -XPCOMUtils.defineLazyServiceGetter(this, "sas", - "@mozilla.org/storage/activity-service;1", - "nsIStorageActivityService"); XPCOMUtils.defineLazyServiceGetter(this, "quotaManagerService", "@mozilla.org/dom/quota-manager-service;1", "nsIQuotaManagerService"); @@ -334,70 +330,6 @@ var Sanitizer = { offlineApps: { async clear(range) { await clearData(range, Ci.nsIClearDataService.CLEAR_DOM_STORAGES); - - if (range) { - let principals = sas.getActiveOrigins(range[0], range[1]) - .QueryInterface(Ci.nsIArray); - - let promises = []; - - for (let i = 0; i < principals.length; ++i) { - let principal = principals.queryElementAt(i, Ci.nsIPrincipal); - - if (principal.URI.scheme != "http" && - principal.URI.scheme != "https" && - principal.URI.scheme != "file") { - continue; - } - - // LocalStorage - Services.obs.notifyObservers(null, "browser:purge-domain-data", principal.URI.host); - - // ServiceWorkers - await ServiceWorkerCleanUp.removeFromPrincipal(principal); - - // QuotaManager - promises.push(new Promise(r => { - let req = quotaManagerService.clearStoragesForPrincipal(principal, null, false); - req.callback = () => { r(); }; - })); - } - - return Promise.all(promises); - } - - // LocalStorage - Services.obs.notifyObservers(null, "extension:purge-localStorage"); - - // ServiceWorkers - await ServiceWorkerCleanUp.removeAll(); - - // QuotaManager - let promises = []; - await new Promise(resolve => { - quotaManagerService.getUsage(request => { - if (request.resultCode != Cr.NS_OK) { - // We are probably shutting down. We don't want to propagate the - // error, rejecting the promise. - resolve(); - return; - } - - for (let item of request.result) { - let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin); - let uri = principal.URI; - if (uri.scheme == "http" || uri.scheme == "https" || uri.scheme == "file") { - promises.push(new Promise(r => { - let req = quotaManagerService.clearStoragesForPrincipal(principal, null, false); - req.callback = () => { r(); }; - })); - } - } - resolve(); - }); - }); - - return Promise.all(promises); } }, @@ -930,13 +862,13 @@ async function maybeSanitizeSessionPrincipals(principals) { } async function sanitizeSessionPrincipal(principal) { - return Promise.all([ - new Promise(r => { - let req = quotaManagerService.clearStoragesForPrincipal(principal, null, false); - req.callback = () => { r(); }; - }).catch(() => {}), - ServiceWorkerCleanUp.removeFromPrincipal(principal).catch(() => {}), - ]); + await new Promise(resolve => { + let service = Cc["@mozilla.org/clear-data-service;1"] + .getService(Ci.nsIClearDataService); + service.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_DOM_STORAGES, + resolve); + }); } function sanitizeNewTabSegregation() { diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 169747922e46..8040c3d269ae 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -11,12 +11,20 @@ XPCOMUtils.defineLazyModuleGetters(this, { setTimeout: "resource://gre/modules/Timer.jsm", Downloads: "resource://gre/modules/Downloads.jsm", OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", + ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", }); +XPCOMUtils.defineLazyServiceGetter(this, "sas", + "@mozilla.org/storage/activity-service;1", + "nsIStorageActivityService"); + // A Cleaner is an object with 3 methods. These methods must return a Promise // object. Here a description of these methods: // * deleteAll() - this method _must_ exist. When called, it deletes all the // data owned by the cleaner. +// * deleteByPrincipal() - this method is implemented only if the cleaner knows +// how to delete data by nsIPrincipal. If not +// implemented, deleteByHost will be used instead. // * deleteByHost() - this method is implemented only if the cleaner knows // how to delete data by host + originAttributes pattern. If // not implemented, deleteAll() will be used as fallback. @@ -261,6 +269,125 @@ const AppCacheCleaner = { }, }; +const QuotaCleaner = { + deleteByPrincipal(aPrincipal) { + // localStorage + Services.obs.notifyObservers(null, "browser:purge-domain-data", + aPrincipal.URI.host); + + // ServiceWorkers: they must be removed before cleaning QuotaManager. + return ServiceWorkerCleanUp.removeFromPrincipal(aPrincipal) + .then(_ => /* exceptionThrown = */ false, _ => /* exceptionThrown = */ true) + .then(exceptionThrown => { + // QuotaManager + return new Promise((aResolve, aReject) => { + let req = Services.qms.clearStoragesForPrincipal(aPrincipal, null, false); + req.callback = () => { + if (exceptionThrown) { + aReject(); + } else { + aResolve(); + } + }; + }); + }); + }, + + deleteByHost(aHost, aOriginAttributes) { + // localStorage + Services.obs.notifyObservers(null, "browser:purge-domain-data", aHost); + + let exceptionThrown = false; + + // ServiceWorkers: they must be removed before cleaning QuotaManager. + return Promise.all([ + ServiceWorkerCleanUp.removeFromHost("http://" + aHost).catch(_ => { exceptionThrown = true; }), + ServiceWorkerCleanUp.removeFromHost("https://" + aHost).catch(_ => { exceptionThrown = true; }), + ]).then(() => { + // QuotaManager + // delete data from both HTTP and HTTPS sites + let httpURI = Services.io.newURI("http://" + aHost); + let httpsURI = Services.io.newURI("https://" + aHost); + let httpPrincipal = Services.scriptSecurityManager + .createCodebasePrincipal(httpURI, aOriginAttributes); + let httpsPrincipal = Services.scriptSecurityManager + .createCodebasePrincipal(httpsURI, aOriginAttributes); + return Promise.all([ + new Promise(aResolve => { + let req = Services.qms.clearStoragesForPrincipal(httpPrincipal, null, true); + req.callback = () => { aResolve(); }; + }), + new Promise(aResolve => { + let req = Services.qms.clearStoragesForPrincipal(httpsPrincipal, null, true); + req.callback = () => { aResolve(); }; + }), + ]).then(() => { + return exceptionThrown ? Promise.reject() : Promise.resolve(); + }); + }); + }, + + deleteByRange(aFrom, aTo) { + let principals = sas.getActiveOrigins(aFrom, aTo) + .QueryInterface(Ci.nsIArray); + + let promises = []; + for (let i = 0; i < principals.length; ++i) { + let principal = principals.queryElementAt(i, Ci.nsIPrincipal); + + if (principal.URI.scheme != "http" && + principal.URI.scheme != "https" && + principal.URI.scheme != "file") { + continue; + } + + promises.push(this.deleteByPrincipal(principal)); + } + + return Promise.all(promises); + }, + + deleteAll() { + // localStorage + Services.obs.notifyObservers(null, "extension:purge-localStorage"); + + // ServiceWorkers + return ServiceWorkerCleanUp.removeAll() + .then(_ => /* exceptionThrown = */ false, _ => /* exceptionThrown = */ true) + .then(exceptionThrown => { + // QuotaManager + return new Promise((aResolve, aReject) => { + Services.qms.getUsage(aRequest => { + if (aRequest.resultCode != Cr.NS_OK) { + // We are probably shutting down. + if (exceptionThrown) { + aReject(); + } else { + aResolve(); + } + return; + } + + let promises = []; + for (let item of aRequest.result) { + let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(item.origin); + if (principal.URI.scheme == "http" || + principal.URI.scheme == "https" || + principal.URI.scheme == "file") { + promises.push(new Promise(aResolve => { + let req = Services.qms.clearStoragesForPrincipal(principal, null, false); + req.callback = () => { aResolve(); }; + })); + } + } + + Promise.all(promises).then(exceptionThrown ? aReject : aResolve); + }); + }); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -286,6 +413,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_APPCACHE, cleaner: AppCacheCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_DOM_QUOTA, + cleaner: QuotaCleaner, }, ]; this.ClearDataService = function() {}; @@ -322,13 +452,16 @@ ClearDataService.prototype = Object.freeze({ } return this._deleteInternal(aFlags, aCallback, aCleaner => { - // Some of the 'Cleaners' do not support to delete by principal. Let's - // use deleteAll() as fallback. + if ("deleteByPrincipal" in aCleaner && aCleaner.deleteByPrincipal) { + return aCleaner.deleteByPrincipal(aPrincipal); + } + // Some of the 'Cleaners' do not support to delete by principal. Fallback + // is to delete by host. if (aCleaner.deleteByHost) { return aCleaner.deleteByHost(aPrincipal.URI.host, aPrincipal.originAttributes); } - // The user wants to delete data. Let's remove as much as we can. + // Next fallback is to use deleteAll(), but only if this was a user request. if (aIsUserRequest) { return aCleaner.deleteAll(); } diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index d49edfaab331..96c3855896fb 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -123,10 +123,14 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_APPCACHE = 1 << 7; + /** + * LocalStorage, IndexedDB, ServiceWorkers, DOM Cache and so on. + */ + const uint32_t CLEAR_DOM_QUOTA = 1 << 8; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; - const uint32_t CLEAR_DOM_QUOTA = 1 << 8; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; const uint32_t CLEAR_PREDICTOR_CACHE = 1 << 10; const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 11; @@ -157,9 +161,9 @@ interface nsIClearDataService : nsISupports /** * Delete all DOM storages - * TODO: add CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; + * TODO: add CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; */ - const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE; + const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA; /* const uint32_t CLEAR_BROWSER_DATA = CLEAR_DOWNLOADS | CLEAR_PASSWORDS | CLEAR_PERMISSIONS | CLEAR_CONTENT_PREFERENCES | CLEAR_HISTORY | CLEAR_LOGINS; diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 0c079d11f13d..ca18ef43829a 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -9,10 +9,6 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); ChromeUtils.defineModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); -ChromeUtils.defineModuleGetter(this, "Downloads", - "resource://gre/modules/Downloads.jsm"); -ChromeUtils.defineModuleGetter(this, "ServiceWorkerCleanUp", - "resource://gre/modules/ServiceWorkerCleanUp.jsm"); var EXPORTED_SYMBOLS = ["ForgetAboutSite"]; @@ -81,28 +77,6 @@ var ForgetAboutSite = { })); } - // ServiceWorkers - await ServiceWorkerCleanUp.removeFromHost("http://" + aDomain); - await ServiceWorkerCleanUp.removeFromHost("https://" + aDomain); - - // Offline Storages. This must run after the ServiceWorkers promises. - promises.push((async function() { - // delete data from both HTTP and HTTPS sites - let httpURI = NetUtil.newURI("http://" + aDomain); - let httpsURI = NetUtil.newURI("https://" + aDomain); - // Following code section has been reverted to the state before Bug 1238183, - // but added a new argument to clearStoragesForPrincipal() for indicating - // clear all storages under a given origin. - let httpPrincipal = Services.scriptSecurityManager - .createCodebasePrincipal(httpURI, {}); - let httpsPrincipal = Services.scriptSecurityManager - .createCodebasePrincipal(httpsURI, {}); - Services.qms.clearStoragesForPrincipal(httpPrincipal, null, true); - Services.qms.clearStoragesForPrincipal(httpsPrincipal, null, true); - })().catch(ex => { - throw new Error("Exception occured while clearing offline storages: " + ex); - })); - // Content Preferences promises.push((async function() { let cps2 = Cc["@mozilla.org/content-pref/service;1"]. From e247e19c682fc18bf06e34b43fbe9185ff55b848 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:00 +0200 Subject: [PATCH 009/116] Bug 1422365 - Introduce nsIClearDataService - part 9 - network predictor, r=johannh --- browser/modules/Sanitizer.jsm | 8 -------- toolkit/components/cleardata/ClearDataService.js | 14 ++++++++++++++ .../components/cleardata/nsIClearDataService.idl | 6 +++++- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 10 ---------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index ad4979411c73..d40dc3245640 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -361,14 +361,6 @@ var Sanitizer = { seenException = ex; } - try { - let predictor = Cc["@mozilla.org/network/predictor;1"] - .getService(Ci.nsINetworkPredictor); - predictor.reset(); - } catch (ex) { - seenException = ex; - } - if (seenException) { throw seenException; } diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 8040c3d269ae..bffe5459a1e2 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -388,6 +388,17 @@ const QuotaCleaner = { }, }; +const PredictorNetworkCleaner = { + deleteAll() { + // Predictive network data - like cache, no way to clear this per + // domain, so just trash it all + let np = Cc["@mozilla.org/network/predictor;1"]. + getService(Ci.nsINetworkPredictor); + np.reset(); + return Promise.resolve(); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -416,6 +427,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_DOM_QUOTA, cleaner: QuotaCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_PREDICTOR_NETWORK_DATA, + cleaner: PredictorNetworkCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 96c3855896fb..6c104eac1f63 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -128,11 +128,15 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_DOM_QUOTA = 1 << 8; + /** + * Predictor network data + */ + const uint32_t CLEAR_PREDICTOR_NETWORK_DATA = 1 << 9; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; - const uint32_t CLEAR_PREDICTOR_CACHE = 1 << 10; const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 11; const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index ca18ef43829a..df67e34e2505 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -93,16 +93,6 @@ var ForgetAboutSite = { }); })()); - // Predictive network data - like cache, no way to clear this per - // domain, so just trash it all - promises.push((async function() { - let np = Cc["@mozilla.org/network/predictor;1"]. - getService(Ci.nsINetworkPredictor); - np.reset(); - })().catch(ex => { - throw new Error("Exception occured while clearing predictive network data: " + ex); - })); - // Push notifications. promises.push((async function() { var push = Cc["@mozilla.org/push/Service;1"]. From fc9290707743f2c31ff4af23790a055a63a899fd Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:01 +0200 Subject: [PATCH 010/116] Bug 1422365 - Introduce nsIClearDataService - part 10 - push notification, r=johannh --- browser/modules/Sanitizer.jsm | 17 +--------- .../components/cleardata/ClearDataService.js | 33 +++++++++++++++++++ .../cleardata/nsIClearDataService.idl | 10 ++++-- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 11 ------- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index d40dc3245640..9bbd41afef90 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -505,22 +505,7 @@ var Sanitizer = { } // Clear all push notification subscriptions - try { - await new Promise((resolve, reject) => { - let push = Cc["@mozilla.org/push/Service;1"] - .getService(Ci.nsIPushService); - push.clearForDomain("*", status => { - if (Components.isSuccessCode(status)) { - resolve(); - } else { - reject(new Error("Error clearing push subscriptions: " + - status)); - } - }); - }); - } catch (ex) { - seenException = ex; - } + await clearData(range, Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS); TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS", refObj); if (seenException) { diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index bffe5459a1e2..8237bfdc7ee3 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -399,6 +399,36 @@ const PredictorNetworkCleaner = { }, }; +const PushNotificationsCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise((aResolve, aReject) => { + let push = Cc["@mozilla.org/push/Service;1"] + .getService(Ci.nsIPushService); + push.clearForDomain(aHost, aStatus => { + if (!Components.isSuccessCode(aStatus)) { + aReject(); + } else { + aResolve(); + } + }); + }); + }, + + deleteAll() { + return new Promise((aResolve, aReject) => { + let push = Cc["@mozilla.org/push/Service;1"] + .getService(Ci.nsIPushService); + push.clearForDomain("*", aStatus => { + if (!Components.isSuccessCode(aStatus)) { + aReject(); + } else { + aResolve(); + } + }); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -430,6 +460,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_PREDICTOR_NETWORK_DATA, cleaner: PredictorNetworkCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS, + cleaner: PushNotificationsCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 6c104eac1f63..ec11a0ecd1af 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -133,11 +133,15 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_PREDICTOR_NETWORK_DATA = 1 << 9; + /** + * DOM Push notifications + */ + const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 10; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; - const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 11; const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; const uint32_t CLEAR_HISTORY = 1 << 14; @@ -165,9 +169,9 @@ interface nsIClearDataService : nsISupports /** * Delete all DOM storages - * TODO: add CLEAR_DOM_PUSH_NOTIFICATIONS | CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; + * TODO: add CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; */ - const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA; + const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS; /* const uint32_t CLEAR_BROWSER_DATA = CLEAR_DOWNLOADS | CLEAR_PASSWORDS | CLEAR_PERMISSIONS | CLEAR_CONTENT_PREFERENCES | CLEAR_HISTORY | CLEAR_LOGINS; diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index df67e34e2505..646291ba8ad3 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -93,17 +93,6 @@ var ForgetAboutSite = { }); })()); - // Push notifications. - promises.push((async function() { - var push = Cc["@mozilla.org/push/Service;1"]. - getService(Ci.nsIPushService); - push.clearForDomain(aDomain, status => { - if (!Components.isSuccessCode(status)) { - throw new Error("Exception occured while clearing push notifications: " + status); - } - }); - })()); - // HSTS and HPKP promises.push((async function() { let sss = Cc["@mozilla.org/ssservice;1"]. From d48e67a5b637ffe16fa5220c6bb79a958bb27cd5 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:01 +0200 Subject: [PATCH 011/116] Bug 1422365 - Introduce nsIClearDataService - part 11 - history, r=johannh --- browser/modules/Sanitizer.jsm | 30 +++---------------- .../components/cleardata/ClearDataService.js | 21 +++++++++++++ .../cleardata/nsIClearDataService.idl | 10 +++---- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 4 --- 4 files changed, 30 insertions(+), 35 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 9bbd41afef90..86bfb6fd3771 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -335,35 +335,13 @@ var Sanitizer = { history: { async clear(range) { - let seenException; let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_HISTORY", refObj); - try { - if (range) { - await PlacesUtils.history.removeVisitsByFilter({ - beginDate: new Date(range[0] / 1000), - endDate: new Date(range[1] / 1000) - }); - } else { - // Remove everything. - await PlacesUtils.history.clear(); - } - } catch (ex) { - seenException = ex; - } finally { - TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj); - } + await clearData(range, Ci.nsIClearDataService.CLEAR_HISTORY); + TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj); - try { - let clearStartingTime = range ? String(range[0]) : ""; - Services.obs.notifyObservers(null, "browser:purge-session-history", clearStartingTime); - } catch (ex) { - seenException = ex; - } - - if (seenException) { - throw seenException; - } + let clearStartingTime = range ? String(range[0]) : ""; + Services.obs.notifyObservers(null, "browser:purge-session-history", clearStartingTime); } }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 8237bfdc7ee3..94d8729b4d49 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -12,6 +12,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { Downloads: "resource://gre/modules/Downloads.jsm", OfflineAppCacheHelper: "resource://gre/modules/offlineAppCache.jsm", ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm", + PlacesUtils: "resource://gre/modules/PlacesUtils.jsm", }); XPCOMUtils.defineLazyServiceGetter(this, "sas", @@ -429,6 +430,23 @@ const PushNotificationsCleaner = { }, }; +const HistoryCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return PlacesUtils.history.removeByFilter({ host: "." + aHost }); + }, + + deleteByRange(aFrom, aTo) { + return PlacesUtils.history.removeVisitsByFilter({ + beginDate: new Date(aFrom / 1000), + endDate: new Date(aTo / 1000) + }); + }, + + deleteAll() { + return PlacesUtils.history.clear(); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -463,6 +481,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS, cleaner: PushNotificationsCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_HISTORY, + cleaner: HistoryCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index ec11a0ecd1af..63af3aa2b06a 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -138,13 +138,17 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_DOM_PUSH_NOTIFICATIONS = 1 << 10; + /** + * Places history + */ + const uint32_t CLEAR_HISTORY = 1 << 11; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; - const uint32_t CLEAR_HISTORY = 1 << 14; const uint32_t CLEAR_SESSION_HISTORY = 1 << 15; const uint32_t CLEAR_FORMDATA = 1 << 16; const uint32_t CLEAR_AUTH_TOKENS = 1 << 17; @@ -172,10 +176,6 @@ interface nsIClearDataService : nsISupports * TODO: add CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; */ const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS; - - /* - const uint32_t CLEAR_BROWSER_DATA = CLEAR_DOWNLOADS | CLEAR_PASSWORDS | CLEAR_PERMISSIONS | CLEAR_CONTENT_PREFERENCES | CLEAR_HISTORY | CLEAR_LOGINS; - */ }; /** diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 646291ba8ad3..4e67be828e8f 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -7,8 +7,6 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); -ChromeUtils.defineModuleGetter(this, "PlacesUtils", - "resource://gre/modules/PlacesUtils.jsm"); var EXPORTED_SYMBOLS = ["ForgetAboutSite"]; @@ -38,8 +36,6 @@ function hasRootDomain(str, aDomain) { var ForgetAboutSite = { async removeDataFromDomain(aDomain) { - await PlacesUtils.history.removeByFilter({ host: "." + aDomain }); - let promises = []; ["http://", "https://"].forEach(scheme => { From 166327eaa6e9dc2bf8d412417e607309815e2eee Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:01 +0200 Subject: [PATCH 012/116] Bug 1422365 - Introduce nsIClearDataService - part 12 - session history, r=johannh --- browser/modules/Sanitizer.jsm | 6 ++---- .../components/cleardata/ClearDataService.js | 19 +++++++++++++++++++ .../cleardata/nsIClearDataService.idl | 6 +++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 86bfb6fd3771..b71482f7d0c5 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -337,11 +337,9 @@ var Sanitizer = { async clear(range) { let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_HISTORY", refObj); - await clearData(range, Ci.nsIClearDataService.CLEAR_HISTORY); + await clearData(range, Ci.nsIClearDataService.CLEAR_HISTORY | + Ci.nsIClearDataService.CLEAR_SESSION_HISTORY); TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj); - - let clearStartingTime = range ? String(range[0]) : ""; - Services.obs.notifyObservers(null, "browser:purge-session-history", clearStartingTime); } }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 94d8729b4d49..7730a9c91605 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -447,6 +447,22 @@ const HistoryCleaner = { }, }; +const SessionHistoryCleaner = { + deleteByRange(aFrom, aTo) { + return new Promise(aResolve => { + Services.obs.notifyObservers(null, "browser:purge-session-history", String(aFrom)); + aResolve(); + }); + }, + + deleteAll() { + return new Promise(aResolve => { + Services.obs.notifyObservers(null, "browser:purge-session-history"); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -484,6 +500,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_HISTORY, cleaner: HistoryCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_SESSION_HISTORY, + cleaner: SessionHistoryCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 63af3aa2b06a..f728f396d4f7 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -143,13 +143,17 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_HISTORY = 1 << 11; + /** + * Session history + */ + const uint32_t CLEAR_SESSION_HISTORY = 1 << 12; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; - const uint32_t CLEAR_SESSION_HISTORY = 1 << 15; const uint32_t CLEAR_FORMDATA = 1 << 16; const uint32_t CLEAR_AUTH_TOKENS = 1 << 17; const uint32_t CLEAR_LOGINS = 1 << 18; From bd85ed6605f81605a4e61e80c785487e3b25b625 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:01 +0200 Subject: [PATCH 013/116] Bug 1422365 - Introduce nsIClearDataService - part 13 - auth tokens, r=johannh --- browser/modules/Sanitizer.jsm | 6 +----- toolkit/components/cleardata/ClearDataService.js | 14 ++++++++++++++ .../components/cleardata/nsIClearDataService.idl | 6 +++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index b71482f7d0c5..3910b92a14ee 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -421,13 +421,9 @@ var Sanitizer = { async clear(range) { let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_SESSIONS", refObj); + await clearData(range, Ci.nsIClearDataService.CLEAR_AUTH_TOKENS); try { - // clear all auth tokens - let sdr = Cc["@mozilla.org/security/sdr;1"] - .getService(Ci.nsISecretDecoderRing); - sdr.logoutAndTeardown(); - // clear FTP and plain HTTP auth sessions Services.obs.notifyObservers(null, "net:clear-active-logins"); } finally { diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 7730a9c91605..cbcd076154fd 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -463,6 +463,17 @@ const SessionHistoryCleaner = { }, }; +const AuthTokensCleaner = { + deleteAll() { + return new Promise(aResolve => { + let sdr = Cc["@mozilla.org/security/sdr;1"] + .getService(Ci.nsISecretDecoderRing); + sdr.logoutAndTeardown(); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -503,6 +514,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_SESSION_HISTORY, cleaner: SessionHistoryCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_AUTH_TOKENS, + cleaner: AuthTokensCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index f728f396d4f7..611b1fe12dca 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -148,6 +148,11 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_SESSION_HISTORY = 1 << 12; + /** + * Auth tokens + */ + const uint32_t CLEAR_AUTH_TOKENS = 1 << 13; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; @@ -155,7 +160,6 @@ interface nsIClearDataService : nsISupports const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; const uint32_t CLEAR_FORMDATA = 1 << 16; - const uint32_t CLEAR_AUTH_TOKENS = 1 << 17; const uint32_t CLEAR_LOGINS = 1 << 18; */ From fe0853f6f2eb92097fdaf17823d7624522441282 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:01 +0200 Subject: [PATCH 014/116] Bug 1422365 - Introduce nsIClearDataService - part 14 - logins, r=johannh --- browser/modules/Sanitizer.jsm | 11 +++-------- toolkit/components/cleardata/ClearDataService.js | 12 ++++++++++++ toolkit/components/cleardata/nsIClearDataService.idl | 6 +++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 3910b92a14ee..58ac864fb6e4 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -421,14 +421,9 @@ var Sanitizer = { async clear(range) { let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_SESSIONS", refObj); - await clearData(range, Ci.nsIClearDataService.CLEAR_AUTH_TOKENS); - - try { - // clear FTP and plain HTTP auth sessions - Services.obs.notifyObservers(null, "net:clear-active-logins"); - } finally { - TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS", refObj); - } + await clearData(range, Ci.nsIClearDataService.CLEAR_AUTH_TOKENS | + Ci.nsIClearDataService.CLEAR_AUTH_CACHE); + TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS", refObj); } }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index cbcd076154fd..bf00fe9ef398 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -474,6 +474,15 @@ const AuthTokensCleaner = { }, }; +const AuthCacheCleaner = { + deleteAll() { + return new Promise(aResolve => { + Services.obs.notifyObservers(null, "net:clear-active-logins"); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -517,6 +526,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_AUTH_TOKENS, cleaner: AuthTokensCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_AUTH_CACHE, + cleaner: AuthCacheCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 611b1fe12dca..655cfa2dd50c 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -153,6 +153,11 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_AUTH_TOKENS = 1 << 13; + /** + * Login cache + */ + const uint32_t CLEAR_AUTH_CACHE = 1 << 14; + /* TODO const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_PERMISSIONS = 1 << 7; @@ -160,7 +165,6 @@ interface nsIClearDataService : nsISupports const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; const uint32_t CLEAR_FORMDATA = 1 << 16; - const uint32_t CLEAR_LOGINS = 1 << 18; */ /** From 18aa82d9fc334a5be7cfce0e05700e122b2757d7 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:30:50 +0200 Subject: [PATCH 015/116] Bug 1422365 - Introduce nsIClearDataService - part 15 - permissions and preferences, r=johannh --- browser/modules/Sanitizer.jsm | 33 +------- .../components/cleardata/ClearDataService.js | 76 +++++++++++++++++++ .../cleardata/nsIClearDataService.idl | 13 +++- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 58 -------------- .../test/unit/test_removeDataFromDomain.js | 15 ++-- 5 files changed, 99 insertions(+), 96 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 58ac864fb6e4..6917e2092b9b 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -433,33 +433,9 @@ var Sanitizer = { let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_SITESETTINGS", refObj); - let startDateMS = range ? range[0] / 1000 : null; - - try { - // Clear site-specific permissions like "Allow this site to open popups" - // we ignore the "end" range and hope it is now() - none of the - // interfaces used here support a true range anyway. - if (startDateMS == null) { - Services.perms.removeAll(); - } else { - Services.perms.removeAllSince(startDateMS); - } - } catch (ex) { - seenException = ex; - } - - try { - // Clear site-specific settings like page-zoom level - let cps = Cc["@mozilla.org/content-pref/service;1"] - .getService(Ci.nsIContentPrefService2); - if (startDateMS == null) { - cps.removeAllDomains(null); - } else { - cps.removeAllDomainsSince(startDateMS, null); - } - } catch (ex) { - seenException = ex; - } + await clearData(range, Ci.nsIClearDataService.CLEAR_PERMISSIONS | + Ci.nsIClearDataService.CLEAR_PREFERENCES | + Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS); try { // Clear site security settings - no support for ranges in this @@ -471,9 +447,6 @@ var Sanitizer = { seenException = ex; } - // Clear all push notification subscriptions - await clearData(range, Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS); - TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS", refObj); if (seenException) { throw seenException; diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index bf00fe9ef398..56bb43e26abf 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -483,6 +483,76 @@ const AuthCacheCleaner = { }, }; +const PermissionsCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise(aResolve => { + let enumerator = Services.perms.enumerator; + while (enumerator.hasMoreElements()) { + let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission); + try { + if (hasRootDomain(perm.principal.URI.host, aHost)) { + Services.perms.removePermission(perm); + } + } catch (ex) { + // Ignore entry + } + } + + aResolve(); + }); + }, + + deleteByRange(aFrom, aTo) { + Services.perms.removeAllSince(aFrom / 1000); + return Promise.resolve(); + }, + + deleteAll() { + Services.perms.removeAll(); + return Promise.resolve(); + }, +}; + +const PreferencesCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise((aResolve, aReject) => { + let cps2 = Cc["@mozilla.org/content-pref/service;1"] + .getService(Ci.nsIContentPrefService2); + cps2.removeBySubdomain(aHost, null, { + handleCompletion: aReason => { + // Notify other consumers, including extensions + Services.obs.notifyObservers(null, "browser:purge-domain-data", + aHost); + if (aReason === cps2.COMPLETE_ERROR) { + aReject(); + } else { + aResolve(); + } + }, + handleError() {} + }); + }); + }, + + deleteByRange(aFrom, aTo) { + return new Promise(aResolve => { + let cps2 = Cc["@mozilla.org/content-pref/service;1"] + .getService(Ci.nsIContentPrefService2); + cps2.removeAllDomainsSince(aFrom / 1000, null); + aResolve(); + }); + }, + + deleteAll() { + return new Promise(aResolve => { + let cps2 = Cc["@mozilla.org/content-pref/service;1"] + .getService(Ci.nsIContentPrefService2); + cps2.removeAllDomains(null); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -529,6 +599,12 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_AUTH_CACHE, cleaner: AuthCacheCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_PERMISSIONS, + cleaner: PermissionsCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_CONTENT_PREFERENCES, + cleaner: PreferencesCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 655cfa2dd50c..3ac66890b374 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -158,10 +158,18 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_AUTH_CACHE = 1 << 14; + /** + * Site permissions + */ + const uint32_t CLEAR_PERMISSIONS = 1 << 15; + + /** + * Site preferences + */ + const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 16; + /* TODO const uint32_t CLEAR_EME = 1 << 4; - const uint32_t CLEAR_PERMISSIONS = 1 << 7; - const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 9; const uint32_t CLEAR_HSTS = 1 << 12; const uint32_t CLEAR_HPKP = 1 << 13; const uint32_t CLEAR_FORMDATA = 1 << 16; @@ -185,7 +193,6 @@ interface nsIClearDataService : nsISupports /** * Delete all DOM storages - * TODO: add CLEAR_FORMDATA | CLEAR_SESSION_HISTORY; */ const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS; }; diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 4e67be828e8f..acbcec740348 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -10,30 +10,6 @@ ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); var EXPORTED_SYMBOLS = ["ForgetAboutSite"]; -/** - * Returns true if the string passed in is part of the root domain of the - * current string. For example, if this is "www.mozilla.org", and we pass in - * "mozilla.org", this will return true. It would return false the other way - * around. - */ -function hasRootDomain(str, aDomain) { - let index = str.indexOf(aDomain); - // If aDomain is not found, we know we do not have it as a root domain. - if (index == -1) - return false; - - // If the strings are the same, we obviously have a match. - if (str == aDomain) - return true; - - // Otherwise, we have aDomain as our root domain iff the index of aDomain is - // aDomain.length subtracted from our length and (since we do not have an - // exact match) the character before the index is a dot or slash. - let prevChar = str[index - 1]; - return (index == (str.length - aDomain.length)) && - (prevChar == "." || prevChar == "/"); -} - var ForgetAboutSite = { async removeDataFromDomain(aDomain) { let promises = []; @@ -55,40 +31,6 @@ var ForgetAboutSite = { throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); })); - // Permissions - // Enumerate all of the permissions, and if one matches, remove it - let enumerator = Services.perms.enumerator; - while (enumerator.hasMoreElements()) { - let perm = enumerator.getNext().QueryInterface(Ci.nsIPermission); - promises.push(new Promise((resolve, reject) => { - try { - if (hasRootDomain(perm.principal.URI.host, aDomain)) { - Services.perms.removePermission(perm); - } - } catch (ex) { - // Ignore entry - } finally { - resolve(); - } - })); - } - - // Content Preferences - promises.push((async function() { - let cps2 = Cc["@mozilla.org/content-pref/service;1"]. - getService(Ci.nsIContentPrefService2); - cps2.removeBySubdomain(aDomain, null, { - handleCompletion: (reason) => { - // Notify other consumers, including extensions - Services.obs.notifyObservers(null, "browser:purge-domain-data", aDomain); - if (reason === cps2.COMPLETE_ERROR) { - throw new Error("Exception occured while clearing content preferences"); - } - }, - handleError() {} - }); - })()); - // HSTS and HPKP promises.push((async function() { let sss = Cc["@mozilla.org/ssservice;1"]. diff --git a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js index 02281652eddb..009bd759217c 100644 --- a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js +++ b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js @@ -338,8 +338,9 @@ async function test_content_preferences_cleared_with_direct_match() { Assert.equal(false, await preference_exists(TEST_URI)); await add_preference(TEST_URI); Assert.ok(await preference_exists(TEST_URI)); + let promisePurgeNotification = waitForPurgeNotification(); await ForgetAboutSite.removeDataFromDomain("mozilla.org"); - await waitForPurgeNotification(); + await promisePurgeNotification; Assert.equal(false, await preference_exists(TEST_URI)); } @@ -348,8 +349,9 @@ async function test_content_preferences_cleared_with_subdomain() { Assert.equal(false, await preference_exists(TEST_URI)); await add_preference(TEST_URI); Assert.ok(await preference_exists(TEST_URI)); + let promisePurgeNotification = waitForPurgeNotification(); await ForgetAboutSite.removeDataFromDomain("mozilla.org"); - await waitForPurgeNotification(); + await promisePurgeNotification; Assert.equal(false, await preference_exists(TEST_URI)); } @@ -358,13 +360,15 @@ async function test_content_preferences_not_cleared_with_uri_contains_domain() { Assert.equal(false, await preference_exists(TEST_URI)); await add_preference(TEST_URI); Assert.ok(await preference_exists(TEST_URI)); + let promisePurgeNotification = waitForPurgeNotification(); await ForgetAboutSite.removeDataFromDomain("mozilla.org"); - await waitForPurgeNotification(); + await promisePurgeNotification; Assert.ok(await preference_exists(TEST_URI)); // Reset state + promisePurgeNotification = waitForPurgeNotification(); await ForgetAboutSite.removeDataFromDomain("ilovemozilla.org"); - await waitForPurgeNotification(); + await promisePurgeNotification; Assert.equal(false, await preference_exists(TEST_URI)); } @@ -483,8 +487,9 @@ async function test_storage_cleared() { Assert.equal(storage.getItem("test"), "value" + i); } + let promisePurgeNotification = waitForPurgeNotification(); await ForgetAboutSite.removeDataFromDomain("mozilla.org"); - await waitForPurgeNotification(); + await promisePurgeNotification; Assert.equal(s[0].getItem("test"), null); Assert.equal(s[0].length, 0); From ebedd40a1215511375ee35ef938bb128db3796b8 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:31:02 +0200 Subject: [PATCH 016/116] Bug 1422365 - Introduce nsIClearDataService - part 16 - security settings, r=johannh --- browser/modules/Sanitizer.jsm | 19 +-------- .../components/cleardata/ClearDataService.js | 40 +++++++++++++++++++ .../cleardata/nsIClearDataService.idl | 7 +++- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 24 ----------- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index 6917e2092b9b..c3495749726a 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -429,28 +429,13 @@ var Sanitizer = { siteSettings: { async clear(range) { - let seenException; let refObj = {}; TelemetryStopwatch.start("FX_SANITIZE_SITESETTINGS", refObj); - await clearData(range, Ci.nsIClearDataService.CLEAR_PERMISSIONS | Ci.nsIClearDataService.CLEAR_PREFERENCES | - Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS); - - try { - // Clear site security settings - no support for ranges in this - // interface either, so we clearAll(). - let sss = Cc["@mozilla.org/ssservice;1"] - .getService(Ci.nsISiteSecurityService); - sss.clearAll(); - } catch (ex) { - seenException = ex; - } - + Ci.nsIClearDataService.CLEAR_DOM_PUSH_NOTIFICATIONS | + Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS); TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS", refObj); - if (seenException) { - throw seenException; - } } }, diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 56bb43e26abf..8e9e9e915d8b 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -553,6 +553,43 @@ const PreferencesCleaner = { }, }; +const SecuritySettingsCleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise(aResolve => { + let sss = Cc["@mozilla.org/ssservice;1"] + .getService(Ci.nsISiteSecurityService); + for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS, + Ci.nsISiteSecurityService.HEADER_HPKP]) { + // Also remove HSTS/HPKP/OMS information for subdomains by enumerating + // the information in the site security service. + let enumerator = sss.enumerate(type); + while (enumerator.hasMoreElements()) { + let entry = enumerator.getNext(); + let hostname = entry.QueryInterface(Ci.nsISiteSecurityState).hostname; + if (hasRootDomain(hostname, aHost)) { + // This uri is used as a key to remove the state. + let uri = Services.io.newURI("https://" + hostname); + sss.removeState(type, uri, 0, entry.originAttributes); + } + } + } + + aResolve(); + }); + }, + + deleteAll() { + return new Promise(aResolve => { + // Clear site security settings - no support for ranges in this + // interface either, so we clearAll(). + let sss = Cc["@mozilla.org/ssservice;1"] + .getService(Ci.nsISiteSecurityService); + sss.clearAll(); + aResolve(); + }); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -605,6 +642,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_CONTENT_PREFERENCES, cleaner: PreferencesCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS, + cleaner: SecuritySettingsCleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 3ac66890b374..466f2d311875 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -168,10 +168,13 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_CONTENT_PREFERENCES = 1 << 16; + /** + * Secure site settings + */ + const uint32_t CLEAR_SECURITY_SETTINGS = 1 << 17; + /* TODO const uint32_t CLEAR_EME = 1 << 4; - const uint32_t CLEAR_HSTS = 1 << 12; - const uint32_t CLEAR_HPKP = 1 << 13; const uint32_t CLEAR_FORMDATA = 1 << 16; */ diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index acbcec740348..42debb7f942c 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -31,30 +31,6 @@ var ForgetAboutSite = { throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); })); - // HSTS and HPKP - promises.push((async function() { - let sss = Cc["@mozilla.org/ssservice;1"]. - getService(Ci.nsISiteSecurityService); - for (let type of [Ci.nsISiteSecurityService.HEADER_HSTS, - Ci.nsISiteSecurityService.HEADER_HPKP]) { - // Also remove HSTS/HPKP information for subdomains by enumerating the - // information in the site security service. - let enumerator = sss.enumerate(type); - while (enumerator.hasMoreElements()) { - let entry = enumerator.getNext(); - let hostname = entry.QueryInterface(Ci.nsISiteSecurityState).hostname; - // If the hostname is aDomain's subdomain, we remove its state. - if (hostname == aDomain || hostname.endsWith("." + aDomain)) { - // This uri is used as a key to remove the state. - let uri = NetUtil.newURI("https://" + hostname); - sss.removeState(type, uri, 0, entry.originAttributes); - } - } - } - })().catch(ex => { - throw new Error("Exception thrown while clearing HSTS/HPKP: " + ex); - })); - let ErrorCount = 0; for (let promise of promises) { try { From 7517b0c5abffc28920c5ee7cb68b22af71cce770 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:31:16 +0200 Subject: [PATCH 017/116] Bug 1422365 - Introduce nsIClearDataService - part 17 - EME data, r=johannh --- .../components/cleardata/ClearDataService.js | 19 ++++++++++ .../cleardata/nsIClearDataService.idl | 6 +++- toolkit/forgetaboutsite/ForgetAboutSite.jsm | 35 +++++++++---------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/toolkit/components/cleardata/ClearDataService.js b/toolkit/components/cleardata/ClearDataService.js index 8e9e9e915d8b..3425e40d411c 100644 --- a/toolkit/components/cleardata/ClearDataService.js +++ b/toolkit/components/cleardata/ClearDataService.js @@ -590,6 +590,22 @@ const SecuritySettingsCleaner = { }, }; +const EMECleaner = { + deleteByHost(aHost, aOriginAttributes) { + return new Promise(aResolve => { + let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"] + .getService(Ci.mozIGeckoMediaPluginChromeService); + mps.forgetThisSite(aHost, JSON.stringify(aOriginAttributes)); + aResolve(); + }); + }, + + deleteAll() { + // Not implemented. + return Promise.resolve(); + }, +}; + // Here the map of Flags-Cleaner. const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_COOKIES, @@ -645,6 +661,9 @@ const FLAGS_MAP = [ { flag: Ci.nsIClearDataService.CLEAR_SECURITY_SETTINGS, cleaner: SecuritySettingsCleaner, }, + + { flag: Ci.nsIClearDataService.CLEAR_EME, + cleaner: EMECleaner, }, ]; this.ClearDataService = function() {}; diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index 466f2d311875..c5dd9bca0c63 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -173,8 +173,12 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_SECURITY_SETTINGS = 1 << 17; + /** + * Media plugin data + */ + const uint32_t CLEAR_EME = 1 << 18; + /* TODO - const uint32_t CLEAR_EME = 1 << 4; const uint32_t CLEAR_FORMDATA = 1 << 16; */ diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 42debb7f942c..23f0e39999c8 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -13,34 +13,31 @@ var EXPORTED_SYMBOLS = ["ForgetAboutSite"]; var ForgetAboutSite = { async removeDataFromDomain(aDomain) { let promises = []; + let errorCount = 0; ["http://", "https://"].forEach(scheme => { promises.push(new Promise(resolve => { Services.clearData.deleteDataFromHost(aDomain, true /* user request */, Ci.nsIClearDataService.CLEAR_ALL, - resolve); + value => { + errorCount += bitCounting(value); + resolve(); + }); })); }); - // EME - promises.push((async function() { - let mps = Cc["@mozilla.org/gecko-media-plugin-service;1"]. - getService(Ci.mozIGeckoMediaPluginChromeService); - mps.forgetThisSite(aDomain, JSON.stringify({})); - })().catch(ex => { - throw new Error("Exception thrown while clearing Encrypted Media Extensions: " + ex); - })); + await Promise.all(promises); - let ErrorCount = 0; - for (let promise of promises) { - try { - await promise; - } catch (ex) { - Cu.reportError(ex); - ErrorCount++; - } + if (errorCount !== 0) { + throw new Error(`There were a total of ${errorCount} errors during removal`); } - if (ErrorCount !== 0) - throw new Error(`There were a total of ${ErrorCount} errors during removal`); } }; + +function bitCounting(value) { + // To know more about how to count bits set to 1 in a numeric value, see this + // interesting article: + // https://blogs.msdn.microsoft.com/jeuge/2005/06/08/bit-fiddling-3/ + const count = value - ((value >> 1) & 0o33333333333) - ((value >> 2) & 0o11111111111); + return ((count + (count >> 3)) & 0o30707070707) % 63; +} From 4eee763067d1140857ec2f077b98f8a8cbdf900e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 14:31:26 +0200 Subject: [PATCH 018/116] Bug 1422365 - Introduce nsIClearDataService - part 18 - custom flags for ForgetAboutSite, r=johannh --- browser/modules/Sanitizer.jsm | 8 ++--- .../cleardata/nsIClearDataService.idl | 17 +++++++---- .../cleardata/tests/unit/test_basic.js | 8 ++--- .../cleardata/tests/unit/test_cookies.js | 30 ++++++------------- .../cleardata/tests/unit/test_downloads.js | 26 ++++------------ toolkit/forgetaboutsite/ForgetAboutSite.jsm | 2 +- 6 files changed, 33 insertions(+), 58 deletions(-) diff --git a/browser/modules/Sanitizer.jsm b/browser/modules/Sanitizer.jsm index c3495749726a..d98d8f55dbc6 100644 --- a/browser/modules/Sanitizer.jsm +++ b/browser/modules/Sanitizer.jsm @@ -765,11 +765,9 @@ async function maybeSanitizeSessionPrincipals(principals) { async function sanitizeSessionPrincipal(principal) { await new Promise(resolve => { - let service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - service.deleteDataFromPrincipal(principal, true /* user request */, - Ci.nsIClearDataService.CLEAR_DOM_STORAGES, - resolve); + Services.clearData.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_DOM_STORAGES, + resolve); }); } diff --git a/toolkit/components/cleardata/nsIClearDataService.idl b/toolkit/components/cleardata/nsIClearDataService.idl index c5dd9bca0c63..ded95c182bd2 100644 --- a/toolkit/components/cleardata/nsIClearDataService.idl +++ b/toolkit/components/cleardata/nsIClearDataService.idl @@ -178,14 +178,10 @@ interface nsIClearDataService : nsISupports */ const uint32_t CLEAR_EME = 1 << 18; - /* TODO - const uint32_t CLEAR_FORMDATA = 1 << 16; - */ - /** * Use this value to delete all the data. */ - const uint32_t CLEAR_ALL = 0xFFFF; + const uint32_t CLEAR_ALL = 0xFFFFFF; /************************************************************************** * The following flags are helpers: they combine some of the previous flags @@ -194,7 +190,6 @@ interface nsIClearDataService : nsISupports /** * Delete all the possible caches. - * TODO: add CLEAR_PREDICTOR_CACHE ? */ const uint32_t CLEAR_ALL_CACHES = CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE; @@ -202,6 +197,16 @@ interface nsIClearDataService : nsISupports * Delete all DOM storages */ const uint32_t CLEAR_DOM_STORAGES = CLEAR_APPCACHE | CLEAR_DOM_QUOTA | CLEAR_DOM_PUSH_NOTIFICATIONS; + + /** + * Helper flag for forget about site + */ + const uint32_t CLEAR_FORGET_ABOUT_SITE = + CLEAR_HISTORY | CLEAR_NETWORK_CACHE | CLEAR_IMAGE_CACHE | CLEAR_COOKIES | + CLEAR_EME | CLEAR_PLUGIN_DATA | CLEAR_DOWNLOADS | CLEAR_PASSWORDS | + CLEAR_PERMISSIONS | CLEAR_DOM_STORAGES | CLEAR_CONTENT_PREFERENCES | + CLEAR_PREDICTOR_NETWORK_DATA | CLEAR_DOM_PUSH_NOTIFICATIONS | + CLEAR_SECURITY_SETTINGS; }; /** diff --git a/toolkit/components/cleardata/tests/unit/test_basic.js b/toolkit/components/cleardata/tests/unit/test_basic.js index 1c0db3661fe0..a29f17cc4400 100644 --- a/toolkit/components/cleardata/tests/unit/test_basic.js +++ b/toolkit/components/cleardata/tests/unit/test_basic.js @@ -7,13 +7,13 @@ "use strict"; +ChromeUtils.import("resource://gre/modules/Services.jsm"); + add_task(async function test_basic() { - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - Assert.ok(!!service); + Assert.ok(!!Services.clearData); await new Promise(aResolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => { Assert.equal(value, 0); aResolve(); }); diff --git a/toolkit/components/cleardata/tests/unit/test_cookies.js b/toolkit/components/cleardata/tests/unit/test_cookies.js index 83e16fc5140d..5470424a15bb 100644 --- a/toolkit/components/cleardata/tests/unit/test_cookies.js +++ b/toolkit/components/cleardata/tests/unit/test_cookies.js @@ -10,10 +10,6 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); add_task(async function test_all_cookies() { - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - Assert.ok(!!service); - const expiry = Date.now() + 24 * 60 * 60; Services.cookies.add("example.net", "path", "name", "value", true /* secure */, true /* http only */, false /* session */, @@ -21,7 +17,7 @@ add_task(async function test_all_cookies() { Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1); await new Promise(aResolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_COOKIES, value => { Assert.equal(value, 0); aResolve(); }); @@ -31,10 +27,6 @@ add_task(async function test_all_cookies() { }); add_task(async function test_range_cookies() { - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - Assert.ok(!!service); - const expiry = Date.now() + 24 * 60 * 60; Services.cookies.add("example.net", "path", "name", "value", true /* secure */, true /* http only */, false /* session */, @@ -44,8 +36,8 @@ add_task(async function test_range_cookies() { // The cookie is out of time range here. let from = Date.now() + 60 * 60; await new Promise(aResolve => { - service.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, - Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Services.clearData.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { Assert.equal(value, 0); aResolve(); }); @@ -56,8 +48,8 @@ add_task(async function test_range_cookies() { // Now we delete all. from = Date.now() - 60 * 60; await new Promise(aResolve => { - service.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, - Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Services.clearData.deleteDataInTimeRange(from * 1000, expiry * 2000, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { Assert.equal(value, 0); aResolve(); }); @@ -67,10 +59,6 @@ add_task(async function test_range_cookies() { }); add_task(async function test_principal_cookies() { - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - Assert.ok(!!service); - const expiry = Date.now() + 24 * 60 * 60; Services.cookies.add("example.net", "path", "name", "value", true /* secure */, true /* http only */, false /* session */, @@ -80,8 +68,8 @@ add_task(async function test_principal_cookies() { let uri = Services.io.newURI("http://example.com"); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); await new Promise(aResolve => { - service.deleteDataFromPrincipal(principal, true /* user request */, - Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Services.clearData.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { Assert.equal(value, 0); aResolve(); }); @@ -93,8 +81,8 @@ add_task(async function test_principal_cookies() { uri = Services.io.newURI("http://example.net"); principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); await new Promise(aResolve => { - service.deleteDataFromPrincipal(principal, true /* user request */, - Ci.nsIClearDataService.CLEAR_COOKIES, value => { + Services.clearData.deleteDataFromPrincipal(principal, true /* user request */, + Ci.nsIClearDataService.CLEAR_COOKIES, value => { Assert.equal(value, 0); aResolve(); }); diff --git a/toolkit/components/cleardata/tests/unit/test_downloads.js b/toolkit/components/cleardata/tests/unit/test_downloads.js index 52a8b35c8858..adb6e8cc9cb3 100644 --- a/toolkit/components/cleardata/tests/unit/test_downloads.js +++ b/toolkit/components/cleardata/tests/unit/test_downloads.js @@ -38,11 +38,6 @@ async function createDownloadList() { add_task(async function test_all_downloads() { const url = createFileURL(); - - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - Assert.ok(!!service); - const list = await createDownloadList(); // First download. @@ -66,7 +61,7 @@ add_task(async function test_all_downloads() { Assert.equal(items.length, 2); await new Promise(resolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { Assert.equal(value, 0); resolve(); }); @@ -80,7 +75,7 @@ add_task(async function test_all_downloads() { await download.cancel(); await new Promise(resolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { Assert.equal(value, 0); resolve(); }); @@ -92,12 +87,6 @@ add_task(async function test_all_downloads() { add_task(async function test_range_downloads() { const url = createFileURL(); - - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - - Assert.ok(!!service); - const list = await createDownloadList(); let download = await Downloads.createDownload({ @@ -115,7 +104,7 @@ add_task(async function test_range_downloads() { Assert.equal(items.length, 1); await new Promise(resolve => { - service.deleteDataInTimeRange(download.startTime.getTime() * 1000, + Services.clearData.deleteDataInTimeRange(download.startTime.getTime() * 1000, download.startTime.getTime() * 1000, true /* user request */, Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { @@ -129,11 +118,6 @@ add_task(async function test_range_downloads() { }); add_task(async function test_principal_downloads() { - const service = Cc["@mozilla.org/clear-data-service;1"] - .getService(Ci.nsIClearDataService); - - Assert.ok(!!service); - const list = await createDownloadList(); let download = await Downloads.createDownload({ @@ -157,7 +141,7 @@ add_task(async function test_principal_downloads() { let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); await new Promise(resolve => { - service.deleteDataFromPrincipal(principal, + Services.clearData.deleteDataFromPrincipal(principal, true /* user request */, Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { Assert.equal(value, 0); @@ -169,7 +153,7 @@ add_task(async function test_principal_downloads() { Assert.equal(items.length, 1); await new Promise(resolve => { - service.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { + Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_DOWNLOADS, value => { Assert.equal(value, 0); resolve(); }); diff --git a/toolkit/forgetaboutsite/ForgetAboutSite.jsm b/toolkit/forgetaboutsite/ForgetAboutSite.jsm index 23f0e39999c8..c701608f4a8d 100644 --- a/toolkit/forgetaboutsite/ForgetAboutSite.jsm +++ b/toolkit/forgetaboutsite/ForgetAboutSite.jsm @@ -18,7 +18,7 @@ var ForgetAboutSite = { ["http://", "https://"].forEach(scheme => { promises.push(new Promise(resolve => { Services.clearData.deleteDataFromHost(aDomain, true /* user request */, - Ci.nsIClearDataService.CLEAR_ALL, + Ci.nsIClearDataService.CLEAR_FORGET_ABOUT_SITE, value => { errorCount += bitCounting(value); resolve(); From 51cc7e1f8e7533ad7de335f98f27e44fd606813b Mon Sep 17 00:00:00 2001 From: Franziskus Kiefer Date: Fri, 1 Jun 2018 09:44:01 +0200 Subject: [PATCH 019/116] Bug 1460617 - land NSS 8232a58332dd UPGRADE_NSS_RELEASE, r=me --HG-- extra : rebase_source : a35fb046aab40741eefdb1361e5b323bfa0bc607 --- security/nss/TAG-INFO | 2 +- .../expected-report-libnssutil3.so.txt | 4 ++++ security/nss/cmd/tstclnt/tstclnt.c | 4 ++-- security/nss/coreconf/coreconf.dep | 1 + security/nss/cpputil/scoped_ptrs.h | 2 ++ security/nss/gtests/ssl_gtest/tls_agent.cc | 22 +++++++++++++++---- security/nss/lib/dev/devslot.c | 2 +- security/nss/lib/ssl/ssl3con.c | 9 ++++++-- security/nss/lib/util/nssutil.def | 7 +++++- security/nss/lib/util/secitem.c | 9 ++++++++ security/nss/lib/util/secitem.h | 8 +++++++ 11 files changed, 59 insertions(+), 11 deletions(-) diff --git a/security/nss/TAG-INFO b/security/nss/TAG-INFO index 206d3b172243..d7a486eca8ef 100644 --- a/security/nss/TAG-INFO +++ b/security/nss/TAG-INFO @@ -1 +1 @@ -3d3e34bb7517 +8232a58332dd diff --git a/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt index e69de29bb2d1..efc7d6d67756 100644 --- a/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt +++ b/security/nss/automation/abi-check/expected-report-libnssutil3.so.txt @@ -0,0 +1,4 @@ + +1 Added function: + + 'function SECStatus SECITEM_MakeItem(PLArenaPool*, SECItem*, unsigned char*, unsigned int)' {SECITEM_MakeItem@@NSSUTIL_3.38} diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c index f6956596bf48..6f5a43146ae0 100644 --- a/security/nss/cmd/tstclnt/tstclnt.c +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -1157,7 +1157,7 @@ run() PRInt32 filesReady; PRFileDesc *s = NULL; PRFileDesc *std_out; - PRPollDesc pollset[2]; + PRPollDesc pollset[2] = { { 0 }, { 0 } }; PRBool wrStarted = PR_FALSE; handshakeComplete = PR_FALSE; @@ -1583,7 +1583,7 @@ done: if (s) { PR_Close(s); } - if (requestFile) { + if (requestFile && pollset[STDIN_FD].fd) { PR_Close(pollset[STDIN_FD].fd); } return error; diff --git a/security/nss/coreconf/coreconf.dep b/security/nss/coreconf/coreconf.dep index 5182f75552c8..590d1bfaeee3 100644 --- a/security/nss/coreconf/coreconf.dep +++ b/security/nss/coreconf/coreconf.dep @@ -10,3 +10,4 @@ */ #error "Do not include this header file." + diff --git a/security/nss/cpputil/scoped_ptrs.h b/security/nss/cpputil/scoped_ptrs.h index 8a0b4f5abe1b..6ffef4dd3fbb 100644 --- a/security/nss/cpputil/scoped_ptrs.h +++ b/security/nss/cpputil/scoped_ptrs.h @@ -45,6 +45,7 @@ struct ScopedDelete { void operator()(SEC_PKCS12DecoderContext* dcx) { SEC_PKCS12DecoderFinish(dcx); } + void operator()(CERTDistNames* names) { CERT_FreeDistNames(names); } }; template @@ -78,6 +79,7 @@ SCOPED(PK11Context); SCOPED(PK11GenericObject); SCOPED(SSLResumptionTokenInfo); SCOPED(SEC_PKCS12DecoderContext); +SCOPED(CERTDistNames); #undef SCOPED diff --git a/security/nss/gtests/ssl_gtest/tls_agent.cc b/security/nss/gtests/ssl_gtest/tls_agent.cc index fc536298ca2e..1cd6fe396272 100644 --- a/security/nss/gtests/ssl_gtest/tls_agent.cc +++ b/security/nss/gtests/ssl_gtest/tls_agent.cc @@ -185,6 +185,10 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) { if (rv != SECSuccess) return false; } + ScopedCERTCertList anchors(CERT_NewCertList()); + rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get()); + if (rv != SECSuccess) return false; + if (role_ == SERVER) { EXPECT_TRUE(ConfigServerCert(name_, true)); @@ -192,10 +196,6 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) { EXPECT_EQ(SECSuccess, rv); if (rv != SECSuccess) return false; - ScopedCERTCertList anchors(CERT_NewCertList()); - rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get()); - if (rv != SECSuccess) return false; - rv = SSL_SetMaxEarlyDataSize(ssl_fd(), 1024); EXPECT_EQ(SECSuccess, rv); if (rv != SECSuccess) return false; @@ -256,6 +256,17 @@ void TlsAgent::SetupClientAuth() { reinterpret_cast(this))); } +void CheckCertReqAgainstDefaultCAs(const CERTDistNames* caNames) { + ScopedCERTDistNames expected(CERT_GetSSLCACerts(nullptr)); + + ASSERT_EQ(expected->nnames, caNames->nnames); + + for (size_t i = 0; i < static_cast(expected->nnames); ++i) { + EXPECT_EQ(SECEqual, + SECITEM_CompareItem(&(expected->names[i]), &(caNames->names[i]))); + } +} + SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd, CERTDistNames* caNames, CERTCertificate** clientCert, @@ -264,6 +275,9 @@ SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd, ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd())); EXPECT_TRUE(peerCert) << "Client should be able to see the server cert"; + // See bug 1457716 + // CheckCertReqAgainstDefaultCAs(caNames); + ScopedCERTCertificate cert; ScopedSECKEYPrivateKey priv; if (!TlsAgent::LoadCertificate(agent->name(), &cert, &priv)) { diff --git a/security/nss/lib/dev/devslot.c b/security/nss/lib/dev/devslot.c index ef941f9edd2c..ebd6e6aa5e62 100644 --- a/security/nss/lib/dev/devslot.c +++ b/security/nss/lib/dev/devslot.c @@ -153,7 +153,7 @@ nssSlot_IsTokenPresent( /* set up condition so only one thread is active in this part of the code at a time */ PZ_Lock(slot->isPresentLock); while (slot->isPresentThread) { - PR_WaitCondVar(slot->isPresentCondition, 0); + PR_WaitCondVar(slot->isPresentCondition, PR_INTERVAL_NO_TIMEOUT); } /* if we were one of multiple threads here, the first thread will have * given us the answer, no need to make more queries of the token. */ diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 391647c9e920..dd280d2efe2c 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -6948,8 +6948,10 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, goto alert_loser; /* malformed */ remaining -= 2; + if (SECITEM_MakeItem(ca_list->arena, &node->name, *b, len) != SECSuccess) { + goto no_mem; + } node->name.len = len; - node->name.data = *b; *b += len; *length -= len; remaining -= len; @@ -6977,7 +6979,6 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, return SECSuccess; no_mem: - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; alert_loser: @@ -11400,6 +11401,10 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, /* Increment the expected sequence number */ ss->ssl3.hs.recvMessageSeq++; } + + /* Taint the message so that it's easier to detect UAFs. */ + PORT_Memset(b, 'N', length); + return rv; } diff --git a/security/nss/lib/util/nssutil.def b/security/nss/lib/util/nssutil.def index 936455f6e7df..26e438ba6af2 100644 --- a/security/nss/lib/util/nssutil.def +++ b/security/nss/lib/util/nssutil.def @@ -322,4 +322,9 @@ _NSSUTIL_UTF8ToWide;- _NSSUTIL_Access;- ;- local: ;- *; -;-}; +;+NSSUTIL_3.38 { # NSS Utilities 3.38 release +;+ global: +SECITEM_MakeItem; +;+ local: +;+ *; +;+}; diff --git a/security/nss/lib/util/secitem.c b/security/nss/lib/util/secitem.c index 22c5b1f6e630..1e505a9af18a 100644 --- a/security/nss/lib/util/secitem.c +++ b/security/nss/lib/util/secitem.c @@ -75,6 +75,15 @@ loser: return (NULL); } +SECStatus +SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest, unsigned char *data, + unsigned int len) +{ + SECItem it = { siBuffer, data, len }; + + return SECITEM_CopyItem(arena, dest, &it); +} + SECStatus SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item, unsigned int oldlen, unsigned int newlen) diff --git a/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h index 5b9d0e1748ae..4fb1239382aa 100644 --- a/security/nss/lib/util/secitem.h +++ b/security/nss/lib/util/secitem.h @@ -35,6 +35,14 @@ SEC_BEGIN_PROTOS extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len); +/* Allocate and make an item with the requested contents. + * + * We seem to have mostly given up on SECItemType, so the result is + * always siBuffer. + */ +extern SECStatus SECITEM_MakeItem(PLArenaPool *arena, SECItem *dest, + unsigned char *data, unsigned int len); + /* ** This is a legacy function containing bugs. It doesn't update item->len, ** and it has other issues as described in bug 298649 and bug 298938. From 50bc0980418eb07d932313da0fc4437f63280b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 1 Jun 2018 11:35:57 +0200 Subject: [PATCH 020/116] Bug 1466008: Make will-change honor prefs properly, and clean it up while at it. r=xidorn Will add a test, though in JSConf right now... MozReview-Commit-ID: JyzwaRgf5Ct --- layout/reftests/bugs/1466008-ref.html | 2 + layout/reftests/bugs/1466008.html | 5 + layout/reftests/bugs/reftest.list | 1 + layout/style/nsStyleConsts.h | 2 + .../components/style/properties/gecko.mako.rs | 66 ++----------- .../style/properties/properties.mako.rs | 6 +- .../components/style/values/specified/box.rs | 97 +++++++++++++++++-- 7 files changed, 113 insertions(+), 66 deletions(-) create mode 100644 layout/reftests/bugs/1466008-ref.html create mode 100644 layout/reftests/bugs/1466008.html diff --git a/layout/reftests/bugs/1466008-ref.html b/layout/reftests/bugs/1466008-ref.html new file mode 100644 index 000000000000..7655e88d9f83 --- /dev/null +++ b/layout/reftests/bugs/1466008-ref.html @@ -0,0 +1,2 @@ + +
diff --git a/layout/reftests/bugs/1466008.html b/layout/reftests/bugs/1466008.html new file mode 100644 index 000000000000..dcccfab213de --- /dev/null +++ b/layout/reftests/bugs/1466008.html @@ -0,0 +1,5 @@ + +
+
+
+
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index f81d7613fef4..b586255bb5f9 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -2076,3 +2076,4 @@ pref(layout.css.moz-document.url-prefix-hack.enabled,true) == 1446470.html 10350 pref(layout.css.moz-document.url-prefix-hack.enabled,false) == 1446470-2.html 1035091-ref.html test-pref(layout.css.prefixes.gradients,false) == 1451874.html 1451874-ref.html fuzzy-if(!(webrender&>kWidget),1-2,17500-17500) == 1412375.html 1412375-ref.html +test-pref(layout.css.contain.enabled,false) == 1466008.html 1466008-ref.html diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index 9eda7b2f4189..9201683099cb 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -232,6 +232,8 @@ enum class StyleOrient : uint8_t { }; // See nsStyleDisplay +// +// These need to be in sync with WillChangeBits in box.rs. #define NS_STYLE_WILL_CHANGE_STACKING_CONTEXT (1<<0) #define NS_STYLE_WILL_CHANGE_TRANSFORM (1<<1) #define NS_STYLE_WILL_CHANGE_SCROLL (1<<2) diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index 741aa7b86b42..4b902358866a 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -3515,77 +3515,27 @@ fn static_assert() { pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) { use gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange}; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_OPACITY; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_SCROLL; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_TRANSFORM; - use properties::PropertyId; use properties::longhands::will_change::computed_value::T; - fn will_change_bitfield_from_prop_flags(prop: LonghandId) -> u8 { - use properties::PropertyFlags; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_ABSPOS_CB; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_FIXPOS_CB; - use gecko_bindings::structs::NS_STYLE_WILL_CHANGE_STACKING_CONTEXT; - let servo_flags = prop.flags(); - let mut bitfield = 0; - - if servo_flags.contains(PropertyFlags::CREATES_STACKING_CONTEXT) { - bitfield |= NS_STYLE_WILL_CHANGE_STACKING_CONTEXT; - } - if servo_flags.contains(PropertyFlags::FIXPOS_CB) { - bitfield |= NS_STYLE_WILL_CHANGE_FIXPOS_CB; - } - if servo_flags.contains(PropertyFlags::ABSPOS_CB) { - bitfield |= NS_STYLE_WILL_CHANGE_ABSPOS_CB; - } - - bitfield as u8 - } - - self.gecko.mWillChangeBitField = 0; - match v { - T::AnimateableFeatures(features) => { + T::AnimateableFeatures { features, bits } => { unsafe { Gecko_ClearWillChange(&mut self.gecko, features.len()); } for feature in features.iter() { - if feature.0 == atom!("scroll-position") { - self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_SCROLL as u8; - } else if feature.0 == atom!("opacity") { - self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_OPACITY as u8; - } else if feature.0 == atom!("transform") { - self.gecko.mWillChangeBitField |= NS_STYLE_WILL_CHANGE_TRANSFORM as u8; - } - unsafe { - Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr()); - } - - if let Ok(prop_id) = PropertyId::parse(&feature.0.to_string()) { - match prop_id.as_shorthand() { - Ok(shorthand) => { - for longhand in shorthand.longhands() { - self.gecko.mWillChangeBitField |= - will_change_bitfield_from_prop_flags(longhand); - } - }, - Err(longhand_or_custom) => { - if let PropertyDeclarationId::Longhand(longhand) - = longhand_or_custom { - self.gecko.mWillChangeBitField |= - will_change_bitfield_from_prop_flags(longhand); - } - }, - } + Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr()) } } + + self.gecko.mWillChangeBitField = bits.bits(); }, T::Auto => { unsafe { Gecko_ClearWillChange(&mut self.gecko, 0); } + self.gecko.mWillChangeBitField = 0; }, }; } @@ -3607,6 +3557,7 @@ fn static_assert() { use properties::longhands::will_change::computed_value::T; use gecko_bindings::structs::nsAtom; use values::CustomIdent; + use values::specified::box_::WillChangeBits; if self.gecko.mWillChange.len() == 0 { return T::Auto @@ -3618,7 +3569,10 @@ fn static_assert() { } }).collect(); - T::AnimateableFeatures(custom_idents.into_boxed_slice()) + T::AnimateableFeatures { + features: custom_idents.into_boxed_slice(), + bits: WillChangeBits::from_bits_truncate(self.gecko.mWillChangeBitField), + } } <% impl_shape_source("shape_outside", "mShapeOutside") %> diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index 81e9a09cbe8b..7696f15c8b87 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -1715,7 +1715,8 @@ impl PropertyId { } } - fn non_custom_id(&self) -> Option { + /// Returns the non-custom property id for this property. + pub fn non_custom_id(&self) -> Option { Some(match *self { PropertyId::Custom(_) => return None, PropertyId::Shorthand(shorthand_id) => shorthand_id.into(), @@ -1750,7 +1751,8 @@ impl PropertyId { id.enabled_for_all_content() } - fn allowed_in(&self, context: &ParserContext) -> bool { + /// Returns whether the property is allowed in a given context. + pub fn allowed_in(&self, context: &ParserContext) -> bool { let id = match self.non_custom_id() { // Custom properties are allowed everywhere None => return true, diff --git a/servo/components/style/values/specified/box.rs b/servo/components/style/values/specified/box.rs index f418b39ef7dc..ed118acc74be 100644 --- a/servo/components/style/values/specified/box.rs +++ b/servo/components/style/values/specified/box.rs @@ -7,6 +7,7 @@ use Atom; use cssparser::Parser; use parser::{Parse, ParserContext}; +use properties::{LonghandId, PropertyId, PropertyFlags, PropertyDeclarationId}; use selectors::parser::SelectorParseErrorKind; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; @@ -382,7 +383,15 @@ pub enum WillChange { Auto, /// #[css(comma)] - AnimateableFeatures(#[css(iterable)] Box<[CustomIdent]>), + AnimateableFeatures { + /// The features that are supposed to change. + #[css(iterable)] + features: Box<[CustomIdent]>, + /// A bitfield with the kind of change that the value will create, based + /// on the above field. + #[css(skip)] + bits: WillChangeBits, + }, } impl WillChange { @@ -393,10 +402,72 @@ impl WillChange { } } +bitflags! { + /// The change bits that we care about. + /// + /// These need to be in sync with NS_STYLE_WILL_CHANGE_*. + #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue)] + pub struct WillChangeBits: u8 { + /// Whether the stacking context will change. + const STACKING_CONTEXT = 1 << 0; + /// Whether `transform` will change. + const TRANSFORM = 1 << 1; + /// Whether `scroll-position` will change. + const SCROLL = 1 << 2; + /// Whether `opacity` will change. + const OPACITY = 1 << 3; + /// Fixed pos containing block. + const FIXPOS_CB = 1 << 4; + /// Abs pos containing block. + const ABSPOS_CB = 1 << 5; + } +} + +fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits { + let mut flags = match longhand { + LonghandId::Opacity => WillChangeBits::OPACITY, + LonghandId::Transform => WillChangeBits::TRANSFORM, + _ => WillChangeBits::empty(), + }; + + let property_flags = longhand.flags(); + if property_flags.contains(PropertyFlags::CREATES_STACKING_CONTEXT) { + flags |= WillChangeBits::STACKING_CONTEXT; + } + if property_flags.contains(PropertyFlags::FIXPOS_CB) { + flags |= WillChangeBits::FIXPOS_CB; + } + if property_flags.contains(PropertyFlags::ABSPOS_CB) { + flags |= WillChangeBits::ABSPOS_CB; + } + flags +} + +fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits { + let id = match PropertyId::parse(ident) { + Ok(id) => id, + Err(..) => return WillChangeBits::empty(), + }; + + if !id.allowed_in(context) { + return WillChangeBits::empty(); + } + + match id.as_shorthand() { + Ok(shorthand) => { + shorthand.longhands().fold(WillChangeBits::empty(), |flags, p| { + flags | change_bits_for_longhand(p) + }) + } + Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand), + Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(), + } +} + impl Parse for WillChange { /// auto | # fn parse<'i, 't>( - _context: &ParserContext, + context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { if input @@ -406,18 +477,28 @@ impl Parse for WillChange { return Ok(WillChange::Auto); } + let mut bits = WillChangeBits::empty(); let custom_idents = input.parse_comma_separated(|i| { let location = i.current_source_location(); - CustomIdent::from_ident( + let parser_ident = i.expect_ident()?; + let ident = CustomIdent::from_ident( location, - i.expect_ident()?, + parser_ident, &["will-change", "none", "all", "auto"], - ) + )?; + + if ident.0 == atom!("scroll-position") { + bits |= WillChangeBits::SCROLL; + } else { + bits |= change_bits_for_maybe_property(&parser_ident, context); + } + Ok(ident) })?; - Ok(WillChange::AnimateableFeatures( - custom_idents.into_boxed_slice(), - )) + Ok(WillChange::AnimateableFeatures { + features: custom_idents.into_boxed_slice(), + bits, + }) } } From 5c22d25db8a2873e13aec602a59b87b36f03e701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 1 Jun 2018 14:00:57 +0200 Subject: [PATCH 021/116] Bug 1466095: Make PropertyId::parse less of a footgun. r=xidorn MozReview-Commit-ID: 2BmtSDPmHj9 --- .../style/properties/declaration_block.rs | 2 +- .../style/properties/properties.mako.rs | 47 +++++++++++++------ .../style/stylesheets/keyframes_rule.rs | 9 ++-- .../style/stylesheets/supports_rule.rs | 6 +-- .../components/style/values/specified/box.rs | 6 +-- servo/ports/geckolib/glue.rs | 20 +++----- 6 files changed, 50 insertions(+), 40 deletions(-) diff --git a/servo/components/style/properties/declaration_block.rs b/servo/components/style/properties/declaration_block.rs index 0263de83fef8..a66058caf1ef 100644 --- a/servo/components/style/properties/declaration_block.rs +++ b/servo/components/style/properties/declaration_block.rs @@ -1158,7 +1158,7 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for PropertyDeclarationParser<'a, 'b> { name: CowRcStr<'i>, input: &mut Parser<'i, 't>, ) -> Result> { - let id = match PropertyId::parse(&name) { + let id = match PropertyId::parse(&name, self.context) { Ok(id) => id, Err(..) => { return Err(input.new_custom_error(if is_non_mozilla_vendor_identifier(&name) { diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index 7696f15c8b87..9ce7d3dfc38c 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -1595,7 +1595,7 @@ impl PropertyId { /// Returns a given property from the string `s`. /// /// Returns Err(()) for unknown non-custom properties. - pub fn parse(property_name: &str) -> Result { + fn parse_unchecked(property_name: &str) -> Result { // FIXME(https://github.com/rust-lang/rust/issues/33156): remove this // enum and use PropertyId when stable Rust allows destructors in // statics. @@ -1639,13 +1639,39 @@ impl PropertyId { PropertyId::ShorthandAlias(id, alias) }, None => { - return ::custom_properties::parse_name(property_name).map(|name| { - PropertyId::Custom(::custom_properties::Name::from(name)) - }) + let name = ::custom_properties::parse_name(property_name)?; + PropertyId::Custom(::custom_properties::Name::from(name)) }, }) } + /// Parses a property name, and returns an error if it's unknown or isn't + /// enabled for all content. + #[inline] + pub fn parse_enabled_for_all_content(name: &str) -> Result { + let id = Self::parse_unchecked(name)?; + + if !id.enabled_for_all_content() { + return Err(()); + } + + Ok(id) + } + + + /// Parses a property name, and returns an error if it's unknown or isn't + /// allowed in this context. + #[inline] + pub fn parse(name: &str, context: &ParserContext) -> Result { + let id = Self::parse_unchecked(name)?; + + if !id.allowed_in(context) { + return Err(()); + } + + Ok(id) + } + /// Returns a property id from Gecko's nsCSSPropertyID. #[cfg(feature = "gecko")] #[allow(non_upper_case_globals)] @@ -1715,8 +1741,7 @@ impl PropertyId { } } - /// Returns the non-custom property id for this property. - pub fn non_custom_id(&self) -> Option { + fn non_custom_id(&self) -> Option { Some(match *self { PropertyId::Custom(_) => return None, PropertyId::Shorthand(shorthand_id) => shorthand_id.into(), @@ -1751,8 +1776,7 @@ impl PropertyId { id.enabled_for_all_content() } - /// Returns whether the property is allowed in a given context. - pub fn allowed_in(&self, context: &ParserContext) -> bool { + fn allowed_in(&self, context: &ParserContext) -> bool { let id = match self.non_custom_id() { // Custom properties are allowed everywhere None => return true, @@ -1974,12 +1998,7 @@ impl PropertyDeclaration { input: &mut Parser<'i, 't>, ) -> Result<(), ParseError<'i>> { assert!(declarations.is_empty()); - - if !id.allowed_in(context) { - return Err(input.new_custom_error( - StyleParseErrorKind::UnknownProperty(name) - )); - } + debug_assert!(id.allowed_in(context), "{:?}", id); let start = input.state(); match id { diff --git a/servo/components/style/stylesheets/keyframes_rule.rs b/servo/components/style/stylesheets/keyframes_rule.rs index 4de3acbaff56..afe797c12ff9 100644 --- a/servo/components/style/stylesheets/keyframes_rule.rs +++ b/servo/components/style/stylesheets/keyframes_rule.rs @@ -620,9 +620,12 @@ impl<'a, 'b, 'i> DeclarationParser<'i> for KeyframeDeclarationParser<'a, 'b> { name: CowRcStr<'i>, input: &mut Parser<'i, 't>, ) -> Result<(), ParseError<'i>> { - let id = PropertyId::parse(&name).map_err(|()| { - input.new_custom_error(StyleParseErrorKind::UnknownProperty(name.clone())) - })?; + let id = match PropertyId::parse(&name, self.context) { + Ok(id) => id, + Err(()) => return Err(input.new_custom_error( + StyleParseErrorKind::UnknownProperty(name.clone()) + )), + }; // TODO(emilio): Shouldn't this use parse_entirely? PropertyDeclaration::parse_into(self.declarations, id, name, self.context, input)?; diff --git a/servo/components/style/stylesheets/supports_rule.rs b/servo/components/style/stylesheets/supports_rule.rs index d94a9a0202ab..5e2739d153dd 100644 --- a/servo/components/style/stylesheets/supports_rule.rs +++ b/servo/components/style/stylesheets/supports_rule.rs @@ -315,12 +315,12 @@ impl Declaration { let mut input = ParserInput::new(&self.0); let mut input = Parser::new(&mut input); - input - .parse_entirely(|input| -> Result<(), CssParseError<()>> { + input.parse_entirely(|input| -> Result<(), CssParseError<()>> { let prop = input.expect_ident_cloned().unwrap(); input.expect_colon().unwrap(); - let id = PropertyId::parse(&prop).map_err(|_| input.new_custom_error(()))?; + let id = PropertyId::parse(&prop, context) + .map_err(|_| input.new_custom_error(()))?; let mut declarations = SourcePropertyDeclaration::new(); input.parse_until_before(Delimiter::Bang, |input| { diff --git a/servo/components/style/values/specified/box.rs b/servo/components/style/values/specified/box.rs index ed118acc74be..dcce3d592ab2 100644 --- a/servo/components/style/values/specified/box.rs +++ b/servo/components/style/values/specified/box.rs @@ -444,15 +444,11 @@ fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits { } fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits { - let id = match PropertyId::parse(ident) { + let id = match PropertyId::parse(ident, context) { Ok(id) => id, Err(..) => return WillChangeBits::empty(), }; - if !id.allowed_in(context) { - return WillChangeBits::empty(); - } - match id.as_shorthand() { Ok(shorthand) => { shorthand.longhands().fold(WillChangeBits::empty(), |flags, p| { diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index cd1c75dcddb3..7c8e48a48b86 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -906,20 +906,12 @@ pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue( macro_rules! parse_enabled_property_name { ($prop_name:ident, $found:ident, $default:expr) => {{ let prop_name = $prop_name.as_ref().unwrap().as_str_unchecked(); - // XXX This can be simplified once Option::filter is stable. - let prop_id = PropertyId::parse(prop_name).ok().and_then(|p| { - if p.enabled_for_all_content() { - Some(p) - } else { - None - } - }); - match prop_id { - Some(p) => { + match PropertyId::parse_enabled_for_all_content(prop_name) { + Ok(p) => { *$found = true; p } - None => { + Err(..) => { *$found = false; return $default; } @@ -941,7 +933,7 @@ pub unsafe extern "C" fn Servo_Property_IsInherited( prop_name: *const nsACString, ) -> bool { let prop_name = prop_name.as_ref().unwrap().as_str_unchecked(); - let prop_id = match PropertyId::parse(prop_name) { + let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) { Ok(id) => id, Err(_) => return false, }; @@ -3476,9 +3468,9 @@ pub extern "C" fn Servo_DeclarationBlock_GetNthProperty( macro_rules! get_property_id_from_property { ($property: ident, $ret: expr) => {{ let property = $property.as_ref().unwrap().as_str_unchecked(); - match PropertyId::parse(property.into()) { + match PropertyId::parse_enabled_for_all_content(property) { Ok(property_id) => property_id, - Err(_) => { return $ret; } + Err(_) => return $ret, } }} } From 15a948f85a4e44519ee9c0e3ac55c71dc6968045 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 15:06:21 +0200 Subject: [PATCH 022/116] Bug 1422365 - Introduce nsIClearDataService - part 19 - android package, r=me CLOSED TREE --- mobile/android/installer/package-manifest.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 199c56b6fe7a..3d4a68abc95b 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -158,8 +158,8 @@ #endif #endif -@RESPATH@/components/ClearDataService.manifest -@RESPATH@/components/ClearDataService.js +@BINPATH@/components/ClearDataService.manifest +@BINPATH@/components/ClearDataService.js @BINPATH@/components/nsUpdateTimerManager.manifest @BINPATH@/components/nsUpdateTimerManager.js From b34aecb22e809673ea76e253214cb4e3dccf07ed Mon Sep 17 00:00:00 2001 From: Simon Fraser Date: Fri, 1 Jun 2018 14:13:44 +0100 Subject: [PATCH 023/116] Bug 1436369 Run blocklist updates on mozilla-beta r=jlorenzo Summary: the blocklist and remote-settings changes need to happen on beta, but not the hsts/hpkp updates, so we have to split out the control of what runs by project. Reviewers: jlorenzo Reviewed By: jlorenzo Bug #: 1436369 Differential Revision: https://phabricator.services.mozilla.com/D1487 --HG-- extra : rebase_source : 19ccbb67b880ee7bd2dc2a37325dd70de635abad --- .cron.yml | 3 ++ taskcluster/ci/repo-update/kind.yml | 38 ++++++++++++++++--- .../taskgraph/transforms/repo_update.py | 27 +++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 taskcluster/taskgraph/transforms/repo_update.py diff --git a/.cron.yml b/.cron.yml index 6e9b753f67f0..1898a4922651 100644 --- a/.cron.yml +++ b/.cron.yml @@ -118,3 +118,6 @@ jobs: mozilla-esr60: - {weekday: 'Monday', hour: 10, minute: 0} - {weekday: 'Thursday', hour: 10, minute: 0} + mozilla-beta: + - {weekday: 'Monday', hour: 10, minute: 0} + - {weekday: 'Thursday', hour: 10, minute: 0} diff --git a/taskcluster/ci/repo-update/kind.yml b/taskcluster/ci/repo-update/kind.yml index 7be1f6da3b9d..b61b1179402a 100644 --- a/taskcluster/ci/repo-update/kind.yml +++ b/taskcluster/ci/repo-update/kind.yml @@ -5,9 +5,41 @@ loader: taskgraph.loader.transform:loader transforms: + - taskgraph.transforms.repo_update:transforms - taskgraph.transforms.task:transforms +job-defaults: + worker: + env: + DO_HSTS: + by-project: + mozilla-central: "1" + mozilla-esr60: "1" + default: "" + DO_HPKP: + by-project: + mozilla-central: "1" + mozilla-esr60: "1" + default: "" + DO_BLOCKLIST: + by-project: + mozilla-central: "1" + mozilla-esr60: "1" + mozilla-beta: "1" + default: "" + DO_REMOTE_SETTINGS: + by-project: + mozilla-central: "1" + mozilla-esr60: "1" + mozilla-beta: "1" + default: "" + USE_MOZILLA_CENTRAL: + by-project: + mozilla-central: "1" + default: "" + + jobs: hsts-hpkp-blocklist: name: periodic_file_update @@ -25,12 +57,6 @@ jobs: docker-image: {in-tree: periodic-updates} max-run-time: 3600 # Sometimes takes ~40 minutes env: - DO_HSTS: "1" - DO_HPKP: "1" - DO_BLOCKLIST: "1" - DO_REMOTE_SETTINGS: "1" - USE_MOZILLA_CENTRAL: "1" - BRANCH: mozilla-central PRODUCT: firefox REVIEWERS: "mtabara, jlund" command: diff --git a/taskcluster/taskgraph/transforms/repo_update.py b/taskcluster/taskgraph/transforms/repo_update.py new file mode 100644 index 000000000000..0f97a93726c4 --- /dev/null +++ b/taskcluster/taskgraph/transforms/repo_update.py @@ -0,0 +1,27 @@ +# 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/. +""" +Transform the repo-update task into an actual task description. +""" + +from __future__ import absolute_import, print_function, unicode_literals + +from taskgraph.transforms.base import TransformSequence +from taskgraph.util.schema import resolve_keyed_by + +transforms = TransformSequence() + + +@transforms.add +def resolve_keys(config, tasks): + for task in tasks: + env = task['worker'].setdefault('env', {}) + env['BRANCH'] = config.params['project'] + for envvar in env: + resolve_keyed_by(env, envvar, envvar, **config.params) + + for envvar in list(env.keys()): + if not env.get(envvar): + del env[envvar] + yield task From f84b6e380c201541d7090bde12260c6bd53fb114 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 1 Jun 2018 09:29:26 -0400 Subject: [PATCH 024/116] Bug 1466090 - use js-bench perfherder framework for jsshell-bench tests. r=ahal --- testing/jsshell/benchmark.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/jsshell/benchmark.py b/testing/jsshell/benchmark.py index 299c2dc9a5f3..2565a97eb915 100644 --- a/testing/jsshell/benchmark.py +++ b/testing/jsshell/benchmark.py @@ -71,7 +71,7 @@ class Benchmark(object): """Resets state between runs.""" self.perfherder_data = { 'framework': { - 'name': 'jsshell-bench', + 'name': 'js-bench', }, 'suites': [ { From 5cf551b94016b6843757febc7c4aaf7cfc7f5841 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 1 Jun 2018 09:29:35 -0400 Subject: [PATCH 025/116] Bug 1392106 - random-if more win7 tests for missing letters. r=RyanVM --- layout/reftests/backgrounds/reftest.list | 12 +-- layout/reftests/bidi/reftest.list | 2 +- layout/reftests/border-radius/reftest.list | 2 +- layout/reftests/bugs/reftest.list | 6 +- layout/reftests/css-calc/reftest.list | 4 +- layout/reftests/css-grid/reftest.list | 36 ++++----- layout/reftests/css-ruby/reftest.list | 6 +- layout/reftests/floats/reftest.list | 72 +++++++++--------- layout/reftests/font-face/reftest.list | 4 +- layout/reftests/font-inflation/reftest.list | 4 +- layout/reftests/mathml/reftest.list | 14 ++-- layout/reftests/selection/reftest.list | 2 +- layout/reftests/svg/reftest.list | 44 +++++------ layout/reftests/svg/smil/style/reftest.list | 12 +-- layout/reftests/text/reftest.list | 2 +- layout/reftests/w3c-css/failures.list | 29 +++---- layout/reftests/w3c-css/received/reftest.list | 76 +++++++++---------- .../submitted/counter-styles-3/reftest.list | 8 +- layout/reftests/writing-mode/reftest.list | 8 +- parser/htmlparser/tests/reftest/reftest.list | 2 +- 20 files changed, 173 insertions(+), 172 deletions(-) diff --git a/layout/reftests/backgrounds/reftest.list b/layout/reftests/backgrounds/reftest.list index 38d060302eed..416139b30324 100644 --- a/layout/reftests/backgrounds/reftest.list +++ b/layout/reftests/backgrounds/reftest.list @@ -178,10 +178,10 @@ fuzzy(30,474) fuzzy-if(skiaContent,31,474) == background-tiling-zoom-1.html back skip-if(!cocoaWidget) == background-repeat-resampling.html background-repeat-resampling-ref.html -fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1a.html background-clip-text-1-ref.html -fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1b.html background-clip-text-1-ref.html -fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1c.html background-clip-text-1-ref.html -fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1d.html background-clip-text-1-ref.html -fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) == background-clip-text-1e.html background-clip-text-1-ref.html +fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1a.html background-clip-text-1-ref.html # Bug 1392106 +fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1b.html background-clip-text-1-ref.html # Bug 1392106 +fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1c.html background-clip-text-1-ref.html # Bug 1392106 +fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1d.html background-clip-text-1-ref.html # Bug 1392106 +fuzzy-if(winWidget,102,2032) fuzzy-if(skiaContent,102,2811) fuzzy-if(webrender&&winWidget,153-153,2866-2866) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-1e.html background-clip-text-1-ref.html # Bug 1392106 -== background-clip-text-2.html background-clip-text-2-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == background-clip-text-2.html background-clip-text-2-ref.html # Bug 1392106 diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list index edda2678e20e..de33e6efc3c9 100644 --- a/layout/reftests/bidi/reftest.list +++ b/layout/reftests/bidi/reftest.list @@ -121,7 +121,7 @@ fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azur fuzzy-if(skiaContent,1,3) == 698291-1.html 698291-1-ref.html == 698706-1.html 698706-1-ref.html == 704837-1.html 704837-1-ref.html -== 712600-1.html 712600-1-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 712600-1.html 712600-1-ref.html # Bug 1392106 == 712600-2.html 712600-2-ref.html == 712600-2-dyn.html 712600-2-ref.html == 712600-3.html 712600-3-ref.html diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list index a071538b4de4..7f37662adb5d 100644 --- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -51,7 +51,7 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html fuzzy-if(true,1,7) fuzzy-if(d2d,55,95) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535 -fuzzy-if(winWidget,105,71) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,21,74) fuzzy-if(d3d11&&advancedLayers,120,319) fuzzy-if(winWidget,144,335) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical +fuzzy-if(winWidget,105,335) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,21,74) fuzzy-if(d3d11&&advancedLayers,120,319) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical, bug 1392106 fuzzy-if(true,2,29) fuzzy-if(d2d,46,71) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html fuzzy-if(cocoaWidget,1,4) fuzzy-if(d2d,59,342) fuzzy-if(d3d11&&advancedLayers&&!d2d,30,3) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index b586255bb5f9..e046a89f84f9 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -695,8 +695,8 @@ fuzzy(37,20) == 379349-1b.xhtml 379349-1-ref.xhtml fuzzy(37,20) == 379349-1c.xhtml 379349-1-ref.xhtml == 379349-2a.xhtml 379349-2-ref.xhtml == 379349-2b.xhtml 379349-2-ref.xhtml -fuzzy-if(Android,2,140) == 379349-3a.xhtml 379349-3-ref.xhtml -fuzzy-if(Android,2,140) == 379349-3b.xhtml 379349-3-ref.xhtml +fuzzy-if(Android,2,140) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 379349-3a.xhtml 379349-3-ref.xhtml # bug 1392106 +fuzzy-if(Android,2,140) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 379349-3b.xhtml 379349-3-ref.xhtml # bug 1392106 == 379361-1.html 379361-1-ref.html == 379361-2.html 379361-2-ref.html == 379361-3.html 379361-3-ref.html @@ -802,7 +802,7 @@ fuzzy-if(skiaContent,1,600) == 393649-1.html 393649-1-ref.html == 393671-1.html 393671-1-ref.html == 393671-2.html 393671-2-ref.html == 393671-3.html 393671-3-ref.html -== 393760-1.xml 393760-1-ref.xml +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 393760-1.xml 393760-1-ref.xml # Bug 1392106 fuzzy-if(skiaContent,1,500) == 393760-2.xml 393760-2-ref.xml == 394111-1.html about:blank # Really an assertion test rather than a rendering test == 394534-1.html 394534-1-ref.html diff --git a/layout/reftests/css-calc/reftest.list b/layout/reftests/css-calc/reftest.list index f8749773fc0b..6538565dd5d4 100644 --- a/layout/reftests/css-calc/reftest.list +++ b/layout/reftests/css-calc/reftest.list @@ -1,3 +1,3 @@ == background-image-gradient-1.html background-image-gradient-1-ref.html -== line-height-1.html line-height-1-ref.html -== line-height-2.html line-height-2-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == line-height-1.html line-height-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == line-height-2.html line-height-2-ref.html # Bug 1392106 diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list index 58d8f99cb9b7..ce29e4d7fd5e 100644 --- a/layout/reftests/css-grid/reftest.list +++ b/layout/reftests/css-grid/reftest.list @@ -37,10 +37,10 @@ skip-if(Android) == grid-placement-definite-implicit-001.html grid-placement-def == grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002-ref.html fuzzy-if(skiaContent,64,1) skip-if(Android) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html == grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html -== rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html -== rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html -== vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html -== vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html # Bug 1392106 == grid-relpos-items-001.html grid-relpos-items-001-ref.html == grid-item-sizing-percent-001.html grid-item-sizing-percent-001-ref.html fails == grid-item-sizing-percent-002.html grid-item-sizing-percent-002-ref.html # bug 1434397 @@ -50,25 +50,25 @@ fails == grid-item-sizing-percent-002.html grid-item-sizing-percent-002-ref.html == grid-item-dir-001.html grid-item-dir-001-ref.html fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-001.html grid-col-max-sizing-max-content-001-ref.html fuzzy-if(winWidget,70,130) fuzzy-if(cocoaWidget,85,180) == grid-col-max-sizing-max-content-002.html grid-col-max-sizing-max-content-002-ref.html -== grid-min-max-content-sizing-001.html grid-min-max-content-sizing-001-ref.html -== grid-min-max-content-sizing-002.html grid-min-max-content-sizing-002-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-max-content-sizing-001.html grid-min-max-content-sizing-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-max-content-sizing-002.html grid-min-max-content-sizing-002-ref.html # Bug 1392106 fuzzy-if(winWidget,1,36) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-definite-001.html grid-auto-min-sizing-definite-001-ref.html # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-intrinsic-001.html grid-auto-min-sizing-intrinsic-001-ref.html # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-intrinsic-002.html grid-auto-min-sizing-intrinsic-002-ref.html # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-intrinsic-003.html grid-auto-min-sizing-intrinsic-003-ref.html # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-intrinsic-004.html grid-auto-min-sizing-intrinsic-004-ref.html # Bug 1392106 -== grid-auto-min-sizing-transferred-size-001.html grid-auto-min-sizing-transferred-size-001-ref.html -== grid-auto-min-sizing-transferred-size-002.html grid-auto-min-sizing-transferred-size-002-ref.html -== grid-auto-min-sizing-transferred-size-003.html grid-auto-min-sizing-transferred-size-003-ref.html -== grid-auto-min-sizing-transferred-size-004.html grid-auto-min-sizing-transferred-size-004-ref.html -== grid-auto-min-sizing-min-content-min-size-001.html grid-auto-min-sizing-min-content-min-size-001-ref.html -== grid-auto-min-sizing-min-content-min-size-002.html grid-auto-min-sizing-min-content-min-size-002-ref.html -== grid-auto-min-sizing-min-content-min-size-003.html grid-auto-min-sizing-min-content-min-size-003-ref.html -== grid-auto-min-sizing-min-content-min-size-004.html grid-auto-min-sizing-min-content-min-size-004-ref.html -== grid-min-content-min-sizing-transferred-size-001.html grid-min-content-min-sizing-transferred-size-001-ref.html -== grid-min-content-min-sizing-transferred-size-002.html grid-min-content-min-sizing-transferred-size-002-ref.html -== grid-min-content-min-sizing-transferred-size-003.html grid-min-content-min-sizing-transferred-size-003-ref.html -== grid-min-content-min-sizing-transferred-size-004.html grid-min-content-min-sizing-transferred-size-004-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-transferred-size-001.html grid-auto-min-sizing-transferred-size-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-transferred-size-002.html grid-auto-min-sizing-transferred-size-002-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-transferred-size-003.html grid-auto-min-sizing-transferred-size-003-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-transferred-size-004.html grid-auto-min-sizing-transferred-size-004-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-min-content-min-size-001.html grid-auto-min-sizing-min-content-min-size-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-min-content-min-size-002.html grid-auto-min-sizing-min-content-min-size-002-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-min-content-min-size-003.html grid-auto-min-sizing-min-content-min-size-003-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-auto-min-sizing-min-content-min-size-004.html grid-auto-min-sizing-min-content-min-size-004-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-001.html grid-min-content-min-sizing-transferred-size-001-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-002.html grid-min-content-min-sizing-transferred-size-002-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-003.html grid-min-content-min-sizing-transferred-size-003-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == grid-min-content-min-sizing-transferred-size-004.html grid-min-content-min-sizing-transferred-size-004-ref.html # Bug 1392106 skip-if(Android) == grid-auto-min-sizing-percent-001.html grid-auto-min-sizing-percent-001-ref.html # bug 1305716 == grid-track-intrinsic-sizing-001.html grid-track-intrinsic-sizing-001-ref.html == grid-track-intrinsic-sizing-002.html grid-track-intrinsic-sizing-002-ref.html diff --git a/layout/reftests/css-ruby/reftest.list b/layout/reftests/css-ruby/reftest.list index 9cc690d0b44a..9071127ec1a0 100644 --- a/layout/reftests/css-ruby/reftest.list +++ b/layout/reftests/css-ruby/reftest.list @@ -20,11 +20,11 @@ test-pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLin == intra-level-whitespace-1.html intra-level-whitespace-1-ref.html == intra-level-whitespace-2.html intra-level-whitespace-2-ref.html == intra-level-whitespace-3.html intra-level-whitespace-3-ref.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == intrinsic-isize-1.html intrinsic-isize-1-ref.html -== intrinsic-isize-2.html intrinsic-isize-2-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == intrinsic-isize-1.html intrinsic-isize-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == intrinsic-isize-2.html intrinsic-isize-2-ref.html # Bug 1392106 == justification-1.html justification-1-ref.html == justification-2.html justification-2-ref.html -fuzzy-if(winWidget,255,792) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == lang-specific-style-1.html lang-specific-style-1-ref.html # bug 1134947 +fuzzy-if(winWidget,255,792) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == lang-specific-style-1.html lang-specific-style-1-ref.html # bug 1134947, Bug 1392106 == line-breaking-1.html line-breaking-1-ref.html == line-breaking-2.html line-breaking-2-ref.html == line-breaking-3.html line-breaking-3-ref.html diff --git a/layout/reftests/floats/reftest.list b/layout/reftests/floats/reftest.list index 8be355d14377..f032a83b94a7 100644 --- a/layout/reftests/floats/reftest.list +++ b/layout/reftests/floats/reftest.list @@ -59,47 +59,47 @@ fuzzy-if(skiaContent,1,12000) == float-in-rtl-4d.html float-in-rtl-4-ref.html == bfc-shrink-1.html bfc-shrink-1-ref.html # Testcases that involve vertical writing mode. -== float-in-rtl-vlr-1a.html float-in-rtl-vlr-1-ref.html -== float-in-rtl-vlr-1b.html float-in-rtl-vlr-1-ref.html -== float-in-rtl-vlr-1c.html float-in-rtl-vlr-1-ref.html -== float-in-rtl-vlr-1d.html float-in-rtl-vlr-1-ref.html -== float-in-rtl-vlr-2a.html float-in-rtl-vlr-2-ref.html -== float-in-rtl-vlr-2b.html float-in-rtl-vlr-2-ref.html -== float-in-rtl-vlr-2c.html float-in-rtl-vlr-2-ref.html -== float-in-rtl-vlr-2d.html float-in-rtl-vlr-2-ref.html -== float-in-rtl-vlr-3a.html float-in-rtl-vlr-3-ref.html -== float-in-rtl-vlr-3b.html float-in-rtl-vlr-3-ref.html -== float-in-rtl-vlr-3c.html float-in-rtl-vlr-3-ref.html -== float-in-rtl-vlr-3d.html float-in-rtl-vlr-3-ref.html -== float-in-rtl-vlr-4a.html float-in-rtl-vlr-4-ref.html -== float-in-rtl-vlr-4b.html float-in-rtl-vlr-4-ref.html -== float-in-rtl-vlr-4c.html float-in-rtl-vlr-4-ref.html -== float-in-rtl-vlr-4d.html float-in-rtl-vlr-4-ref.html -== float-in-rtl-vrl-1a.html float-in-rtl-vrl-1-ref.html -== float-in-rtl-vrl-1b.html float-in-rtl-vrl-1-ref.html -== float-in-rtl-vrl-1c.html float-in-rtl-vrl-1-ref.html -== float-in-rtl-vrl-1d.html float-in-rtl-vrl-1-ref.html -== float-in-rtl-vrl-2a.html float-in-rtl-vrl-2-ref.html -== float-in-rtl-vrl-2b.html float-in-rtl-vrl-2-ref.html -== float-in-rtl-vrl-2c.html float-in-rtl-vrl-2-ref.html -== float-in-rtl-vrl-2d.html float-in-rtl-vrl-2-ref.html -== float-in-rtl-vrl-3a.html float-in-rtl-vrl-3-ref.html -== float-in-rtl-vrl-3b.html float-in-rtl-vrl-3-ref.html -== float-in-rtl-vrl-3c.html float-in-rtl-vrl-3-ref.html -== float-in-rtl-vrl-3d.html float-in-rtl-vrl-3-ref.html -== float-in-rtl-vrl-4a.html float-in-rtl-vrl-4-ref.html -== float-in-rtl-vrl-4b.html float-in-rtl-vrl-4-ref.html -== float-in-rtl-vrl-4c.html float-in-rtl-vrl-4-ref.html -== float-in-rtl-vrl-4d.html float-in-rtl-vrl-4-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-1a.html float-in-rtl-vlr-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-1b.html float-in-rtl-vlr-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-1c.html float-in-rtl-vlr-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-1d.html float-in-rtl-vlr-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-2a.html float-in-rtl-vlr-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-2b.html float-in-rtl-vlr-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-2c.html float-in-rtl-vlr-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-2d.html float-in-rtl-vlr-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-3a.html float-in-rtl-vlr-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-3b.html float-in-rtl-vlr-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-3c.html float-in-rtl-vlr-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-3d.html float-in-rtl-vlr-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-4a.html float-in-rtl-vlr-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-4b.html float-in-rtl-vlr-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-4c.html float-in-rtl-vlr-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vlr-4d.html float-in-rtl-vlr-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-1a.html float-in-rtl-vrl-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-1b.html float-in-rtl-vrl-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-1c.html float-in-rtl-vrl-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-1d.html float-in-rtl-vrl-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-2a.html float-in-rtl-vrl-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-2b.html float-in-rtl-vrl-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-2c.html float-in-rtl-vrl-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-2d.html float-in-rtl-vrl-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-3a.html float-in-rtl-vrl-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-3b.html float-in-rtl-vrl-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-3c.html float-in-rtl-vrl-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-3d.html float-in-rtl-vrl-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-4a.html float-in-rtl-vrl-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-4b.html float-in-rtl-vrl-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-4c.html float-in-rtl-vrl-4-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == float-in-rtl-vrl-4d.html float-in-rtl-vrl-4-ref.html # Bug 1392106 fuzzy-if(OSX==1010,28,11) fuzzy-if(Android,16,2) == orthogonal-floats-1a.html orthogonal-floats-1-ref.html fuzzy-if(OSX==1010,28,11) fuzzy-if(winWidget,137,3) == orthogonal-floats-1b.html orthogonal-floats-1-ref.html fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,135,700) == orthogonal-floats-1c.html orthogonal-floats-1-ref.html fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,135,700) == orthogonal-floats-1d.html orthogonal-floats-1-ref.html -== logical-float-side-1.html logical-float-side-1-ref.html -== logical-float-side-2.html logical-float-side-2-ref.html -== logical-float-side-3.html logical-float-side-3-ref.html -== logical-float-side-4.html logical-float-side-4-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == logical-float-side-1.html logical-float-side-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == logical-float-side-2.html logical-float-side-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == logical-float-side-3.html logical-float-side-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == logical-float-side-4.html logical-float-side-4-ref.html # Bug 1392106 == float-in-rtl-slr-1a.html float-in-rtl-slr-1-ref.html == float-in-rtl-slr-1b.html float-in-rtl-slr-1-ref.html diff --git a/layout/reftests/font-face/reftest.list b/layout/reftests/font-face/reftest.list index 4fb7c759c9cd..2e94970937a5 100644 --- a/layout/reftests/font-face/reftest.list +++ b/layout/reftests/font-face/reftest.list @@ -41,7 +41,7 @@ skip == src-list-local-localized.html src-list-local-localized-ref.html # 486787 # postscript name lookup # fontconfig only supports postscript name lookup from 2.10.92, Android not supported -fails-if(Android) random-if(gtkWidget) == src-list-local-ps.html src-list-local-full-ref.html +fails-if(Android) random-if(gtkWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == src-list-local-ps.html src-list-local-full-ref.html # Bug 1392106 # Mac-specific test of 100 weight faces random-if(!cocoaWidget) == helveticaneue-ultra.html helveticaneue-ultra-ref.html @@ -90,7 +90,7 @@ random-if(cocoaWidget) == sheet-set-switch-1.html sheet-set-switch-1-ref.html # == ex-unit-1.html ex-unit-1-ref.html == ex-unit-1-dynamic.html ex-unit-1-ref.html -== local-1.html local-1-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == local-1.html local-1-ref.html # Bug 1392106 == local-styled-1.html local-styled-1-ref.html == synthetic-weight-style.html synthetic-weight-style-ref.html diff --git a/layout/reftests/font-inflation/reftest.list b/layout/reftests/font-inflation/reftest.list index ab3d2cf6a1a6..e6ae952c60b3 100644 --- a/layout/reftests/font-inflation/reftest.list +++ b/layout/reftests/font-inflation/reftest.list @@ -64,8 +64,8 @@ test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceE test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) != disable-fontinfl-on-mobile-5.html disable-fontinfl-on-mobile-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == preformatted-text.html preformatted-text-ref.html -test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == fixed-height-body.html fixed-height-body-ref.html -test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == fixed-height-body-child.html fixed-height-body-child-ref.html +test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == fixed-height-body.html fixed-height-body-ref.html # Bug 1392106 +test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == fixed-height-body-child.html fixed-height-body-child-ref.html # Bug 1392106 test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.forceEnabled,true) test-pref(font.size.inflation.lineThreshold,0) == consecutive-inline.html consecutive-inline-ref.html # The tests below use nonzero values of the lineThreshold preference. diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index a6cd9b5a2d46..32c262c70b6d 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -187,10 +187,10 @@ random-if(gtkWidget) == mpadded-9.html mpadded-9-ref.html # bug 1309430 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == maction-dynamic-embellished-op.html maction-dynamic-embellished-op-ref.html # Bug 1392106 == maction-dynamic-1.html maction-dynamic-1-ref.html # bug 773482 == maction-dynamic-2.html maction-dynamic-2-ref.html -== mo-lspace-rspace.html mo-lspace-rspace-ref.html -== mo-lspace-rspace-2.html mo-lspace-rspace-2-ref.html -== mo-lspace-rspace-3.html mo-lspace-rspace-3-ref.html -== mo-lspace-rspace-4.html mo-lspace-rspace-4-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mo-lspace-rspace.html mo-lspace-rspace-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mo-lspace-rspace-2.html mo-lspace-rspace-2-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mo-lspace-rspace-3.html mo-lspace-rspace-3-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mo-lspace-rspace-4.html mo-lspace-rspace-4-ref.html # Bug 1392106 == mo-invisibleoperators.html mo-invisibleoperators-ref.html == mo-invisibleoperators-2.html mo-invisibleoperators-2-ref.html random-if(gtkWidget) == mo-glyph-size.html mo-glyph-size-ref.html # bug 1309426 @@ -285,9 +285,9 @@ fuzzy-if(d2d,7,1) == menclose-6-updiagonalstrike.html menclose-6-ref.html == menclose-6-phasorangle.html menclose-6-ref.html == mmultiscript-align.html mmultiscript-align-ref.html fails-if(winWidget) == subscript-italic-correction.html subscript-italic-correction-ref.html # bug 961482 -fails-if(Android) == mathvariant-1a.html mathvariant-1a-ref.html # Bug 1010679 -fails-if(Android) == mathvariant-1b.html mathvariant-1b-ref.html # Bug 1010679 -fails-if(Android) == mathvariant-1c.html mathvariant-1c-ref.html # Bug 1010679 +fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1a.html mathvariant-1a-ref.html # Bug 1010679, Bug 1392106 +fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1b.html mathvariant-1b-ref.html # Bug 1010679, Bug 1392106 +fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == mathvariant-1c.html mathvariant-1c-ref.html # Bug 1010679, Bug 1392106 == mathvariant-1d.html mathvariant-1d-ref.html fails-if(Android||OSX) == mathvariant-2.html mathvariant-2-ref.html # Bugs 1010678, 1010679 == mathvariant-3.html mathvariant-3-ref.html diff --git a/layout/reftests/selection/reftest.list b/layout/reftests/selection/reftest.list index 9983bdd6d7c7..42540415c925 100644 --- a/layout/reftests/selection/reftest.list +++ b/layout/reftests/selection/reftest.list @@ -48,6 +48,6 @@ fuzzy-if(OSX==1010,9,1) fuzzy-if(OSX&&skiaContent&&!webrender,6,1) fuzzy-if(skia == invalidation-2d.html invalidation-2-ref.html == invalidation-2e.html invalidation-2-ref.html == invalidation-2f.html invalidation-2-ref.html -fuzzy(7,2) fuzzy-if(OSX,1,1) fails-if(isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == rtl-selection-with-decoration.html rtl-selection-with-decoration-ref.html +fuzzy(7,2) fuzzy-if(OSX,1,1) fails-if(isDebugBuild&&!browserIsRemote) fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) needs-focus == rtl-selection-with-decoration.html rtl-selection-with-decoration-ref.html # Bug 1392106 fails-if(isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == semitransparent-decoration-line.html semitransparent-decoration-line-ref.html fuzzy-if(OSX,1,6) fails-if(isDebugBuild&&!browserIsRemote) fails-if(Android) needs-focus == writing-mode.html writing-mode-ref.html diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index fffc067e17ac..be240952851d 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -159,10 +159,10 @@ fuzzy-if(d2d&&layersGPUAccelerated,3,1200) == dynamic-rect-02.svg dynamic-rect-0 == dynamic-stroke-opacity-01.svg pass.svg == dynamic-stroke-width-01.svg pass.svg == dynamic-switch-01.svg pass.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-01.svg dynamic-text-01-ref.svg +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-01.svg dynamic-text-01-ref.svg # bug 1392106 fuzzy-if(d2d&&layersGPUAccelerated,3,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8 fuzzy-if(d2d&&layersGPUAccelerated,2,10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7 -fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),47,89) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7 # bug 1392106 == dynamic-text-05.svg pass.svg == dynamic-text-06.svg pass.svg == dynamic-text-07.svg dynamic-text-07-ref.svg @@ -439,7 +439,7 @@ fuzzy-if(skiaContent,1,2600) == svg-in-foreignObject-02.xhtml svg-in-foreignObje == symbol-01.svg symbol-01-ref.svg == text-font-size-01.svg pass.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) random-if(gtkWidget) == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) random-if(gtkWidget) == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713, bug 1392106 == text-gradient-01.svg text-gradient-01-ref.svg random-if(winWidget) fuzzy-if(Android,10,2) == text-gradient-02.svg text-gradient-02-ref.svg # see bug 590101 fuzzy-if(skiaContent,1,5500) == text-gradient-03.svg pass.svg @@ -450,17 +450,17 @@ fuzzy-if(skiaContent,1,5500) == text-gradient-03.svg pass.svg # Tests for bug 546813: sanity-check using HTML text, then test SVG behavior. != text-language-00.xhtml text-language-00-ref.xhtml random-if(gtkWidget) != text-language-01.xhtml text-language-01-ref.xhtml # Fails on Linux tryserver due to lack of CJK fonts. -== text-layout-01.svg text-layout-01-ref.svg -== text-layout-02.svg text-layout-02-ref.svg -== text-layout-03.svg text-layout-03-ref.svg -== text-layout-04.svg text-layout-04-ref.svg -== text-layout-05.svg text-layout-05-ref.svg -fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) == text-layout-06.svg text-layout-06-ref.svg -== text-layout-07.svg text-layout-07-ref.svg -== text-layout-08.svg text-layout-08-ref.svg -== text-scale-01.svg text-scale-01-ref.svg -fuzzy-if(skiaContent,2,1000) == text-scale-02.svg text-scale-02-ref.svg -== text-scale-03.svg text-scale-03-ref.svg +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-01.svg text-layout-01-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-02.svg text-layout-02-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-03.svg text-layout-03-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-04.svg text-layout-04-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-05.svg text-layout-05-ref.svg # Bug 1392106 +fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-06.svg text-layout-06-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-07.svg text-layout-07-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-layout-08.svg text-layout-08-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-01.svg text-scale-01-ref.svg # Bug 1392106 +fuzzy-if(skiaContent,2,1000) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-02.svg text-scale-02-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-scale-03.svg text-scale-03-ref.svg # Bug 1392106 == text-style-01a.svg text-style-01-ref.svg == text-style-01b.svg text-style-01-ref.svg @@ -495,14 +495,14 @@ fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg == tspan-dxdy-05.svg tspan-dxdy-ref.svg == tspan-dxdy-06.svg tspan-dxdy-ref.svg == tspan-dxdy-textPath-01.svg tspan-dxdy-textPath-01-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == tspan-rotate-01.svg tspan-rotate-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-02.svg tspan-rotate-02.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-02.svg tspan-rotate-02-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-03.svg tspan-rotate-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-04.svg tspan-rotate-04.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-04.svg tspan-rotate-04-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-05.svg tspan-rotate-ref.svg -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-06.svg tspan-rotate-ref.svg +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == tspan-rotate-01.svg tspan-rotate-ref.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-02.svg tspan-rotate-02.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-02.svg tspan-rotate-02-ref.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-03.svg tspan-rotate-ref.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-04.svg tspan-rotate-04.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-04.svg tspan-rotate-04-ref.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-05.svg tspan-rotate-ref.svg # bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) fuzzy-if(skiaContent,1,550) == tspan-rotate-06.svg tspan-rotate-ref.svg # bug 1392106 == tspan-rotate-07.svg tspan-rotate-07-ref.svg == tspan-rotate-textPath-01.svg tspan-rotate-textPath-01-ref.svg fuzzy-if(skiaContent,1,100) == tspan-xy-01.svg tspan-xy-ref.svg diff --git a/layout/reftests/svg/smil/style/reftest.list b/layout/reftests/svg/smil/style/reftest.list index 62c04b360359..819df0f585cc 100644 --- a/layout/reftests/svg/smil/style/reftest.list +++ b/layout/reftests/svg/smil/style/reftest.list @@ -79,14 +79,14 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg # Bug 1392106 # 'font-size' mapped attribute (accepts unitless values) -== anim-mapped-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg -== anim-mapped-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg -== anim-mapped-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-mapped-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-mapped-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-mapped-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg # Bug 1392106 # 'font-size' property, from/by/to with percent values -== anim-css-fontsize-1-from-by-pct-pct.svg anim-css-fontsize-1-ref.svg -== anim-css-fontsize-1-from-by-pct-px.svg anim-css-fontsize-1-ref.svg -== anim-css-fontsize-1-from-by-px-pct.svg anim-css-fontsize-1-ref.svg +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-by-pct-pct.svg anim-css-fontsize-1-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-by-pct-px.svg anim-css-fontsize-1-ref.svg # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-by-px-pct.svg anim-css-fontsize-1-ref.svg # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-pct-pct.svg anim-css-fontsize-1-ref.svg # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-pct-px.svg anim-css-fontsize-1-ref.svg # Bug 1392106 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == anim-css-fontsize-1-from-to-px-pct.svg anim-css-fontsize-1-ref.svg # Bug 1392106 diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index eab91ce4c0b2..4964b197d507 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -67,7 +67,7 @@ fuzzy-if(Android,231,653) == subpixel-lineheight-1a.html subpixel-lineheight-1b. == text-align-last-end.html text-align-last-end-ref.html == text-align-last-center.html text-align-last-center-ref.html == text-align-last-justify.html text-align-last-justify-ref.html -== text-align-last-justify-rtl.html text-align-last-justify-rtl-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == text-align-last-justify-rtl.html text-align-last-justify-rtl-ref.html # Bug 1392106 # # Default values: # text-align defaults to start. text-align-last defaults to auto, which is diff --git a/layout/reftests/w3c-css/failures.list b/layout/reftests/w3c-css/failures.list index 713350e40158..dba7591adf2a 100644 --- a/layout/reftests/w3c-css/failures.list +++ b/layout/reftests/w3c-css/failures.list @@ -105,7 +105,7 @@ fuzzy-if(OSX||winWidget,218,621) css-writing-modes/inline-block-alignment-ortho fuzzy-if(OSX||winWidget,135,1080) css-writing-modes/inline-block-alignment-slr-009.xht fuzzy-if(OSX||winWidget,112,960) css-writing-modes/inline-block-alignment-srl-008.xht fuzzy-if(OSX||winWidget,213,1540) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-direction-???-0??.xht -fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/row-progression-???-0??.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/row-progression-???-0??.xht fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/table-column-order-00?.xht fuzzy-if(winWidget,110,1200) fuzzy-if(webrender&&cocoaWidget,1-1,2-2) css-writing-modes/table-column-order-slr-007.xht fuzzy-if(OSX||winWidget,110,1200) css-writing-modes/table-column-order-srl-006.xht @@ -153,16 +153,16 @@ random css-writing-modes/line-box-direction-vlr-016.xht random css-writing-modes/line-box-direction-vrl-015.xht # Bug 1220352 -fails css-writing-modes/line-box-height-vlr-003.xht -fails css-writing-modes/line-box-height-vlr-005.xht -fails css-writing-modes/line-box-height-vlr-011.xht -fails css-writing-modes/line-box-height-vlr-013.xht -fails css-writing-modes/line-box-height-vlr-021.xht -fails css-writing-modes/line-box-height-vlr-023.xht -fails css-writing-modes/line-box-height-vrl-002.xht -fails css-writing-modes/line-box-height-vrl-004.xht -fails css-writing-modes/line-box-height-vrl-010.xht -fails css-writing-modes/line-box-height-vrl-012.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-003.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-005.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-011.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-013.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-021.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vlr-023.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vrl-002.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vrl-004.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vrl-010.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/line-box-height-vrl-012.xht # Bug 1258635 - text-combine-upright: digits skip css-writing-modes/full-width-003.html @@ -331,6 +331,7 @@ skip selectors/selectors-empty-001.xml skip selectors/selectors-namespace-001.xml # Bug 1392106 -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) counter-styles-3/system-cyclic.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) counter-styles-3/dependent-builtin.html -random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) counter-styles-3/redefine-attr-mapping.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/margin-v??-00?.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/padding-v??-00?.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/percent-margin-v??-00?.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) css-writing-modes/percent-padding-v??-00?.xht diff --git a/layout/reftests/w3c-css/received/reftest.list b/layout/reftests/w3c-css/received/reftest.list index d34d277cb1ba..5170980644c7 100644 --- a/layout/reftests/w3c-css/received/reftest.list +++ b/layout/reftests/w3c-css/received/reftest.list @@ -837,20 +837,20 @@ fuzzy-if(OSX||winWidget,213,1540) random-if(/^Windows\x20NT\x206\.1/.test(http.o random == css-writing-modes/line-box-direction-vrl-015.xht css-writing-modes/block-flow-direction-001-ref.xht fuzzy-if(OSX||winWidget,213,1540) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-direction-vrl-017.xht css-writing-modes/block-flow-direction-001-ref.xht fuzzy-if(OSX||winWidget,213,1540) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-direction-vrl-019.xht css-writing-modes/block-flow-direction-001-ref.xht -fails == css-writing-modes/line-box-height-vlr-003.xht css-writing-modes/line-box-height-vlr-003-ref.xht -fails == css-writing-modes/line-box-height-vlr-005.xht css-writing-modes/line-box-height-vlr-003-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-003.xht css-writing-modes/line-box-height-vlr-003-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-005.xht css-writing-modes/line-box-height-vlr-003-ref.xht == css-writing-modes/line-box-height-vlr-007.xht css-writing-modes/line-box-height-vlr-007-ref.xht == css-writing-modes/line-box-height-vlr-009.xht css-writing-modes/line-box-height-vlr-007-ref.xht -fails == css-writing-modes/line-box-height-vlr-011.xht css-writing-modes/line-box-height-vlr-011-ref.xht -fails == css-writing-modes/line-box-height-vlr-013.xht css-writing-modes/line-box-height-vlr-011-ref.xht -fails == css-writing-modes/line-box-height-vlr-021.xht css-writing-modes/line-box-height-vlr-021-ref.xht -fails == css-writing-modes/line-box-height-vlr-023.xht css-writing-modes/line-box-height-vlr-023-ref.xht -fails == css-writing-modes/line-box-height-vrl-002.xht css-writing-modes/line-box-height-vrl-002-ref.xht -fails == css-writing-modes/line-box-height-vrl-004.xht css-writing-modes/line-box-height-vrl-002-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-011.xht css-writing-modes/line-box-height-vlr-011-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-013.xht css-writing-modes/line-box-height-vlr-011-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-021.xht css-writing-modes/line-box-height-vlr-021-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vlr-023.xht css-writing-modes/line-box-height-vlr-023-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vrl-002.xht css-writing-modes/line-box-height-vrl-002-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vrl-004.xht css-writing-modes/line-box-height-vrl-002-ref.xht == css-writing-modes/line-box-height-vrl-006.xht css-writing-modes/line-box-height-vrl-006-ref.xht == css-writing-modes/line-box-height-vrl-008.xht css-writing-modes/line-box-height-vrl-006-ref.xht -fails == css-writing-modes/line-box-height-vrl-010.xht css-writing-modes/line-box-height-vrl-010-ref.xht -fails == css-writing-modes/line-box-height-vrl-012.xht css-writing-modes/line-box-height-vrl-010-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vrl-010.xht css-writing-modes/line-box-height-vrl-010-ref.xht +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/line-box-height-vrl-012.xht css-writing-modes/line-box-height-vrl-010-ref.xht == css-writing-modes/margin-collapse-vlr-003.xht reference/ref-filled-green-100px-square.xht == css-writing-modes/margin-collapse-vlr-009.xht reference/ref-filled-green-100px-square.xht == css-writing-modes/margin-collapse-vlr-011.xht reference/ref-filled-green-100px-square.xht @@ -869,8 +869,8 @@ fails == css-writing-modes/line-box-height-vrl-012.xht css-writing-modes/line-bo == css-writing-modes/margin-collapse-vrl-030.xht reference/ref-filled-green-100px-square.xht == css-writing-modes/margin-collapse-vrl-034.xht reference/ref-filled-green-100px-square.xht == css-writing-modes/margin-collapse-vrl-036.xht reference/ref-filled-green-100px-square.xht -== css-writing-modes/margin-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/margin-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/margin-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/margin-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht == css-writing-modes/normal-flow-overconstrained-vlr-003.xht css-writing-modes/abs-pos-non-replaced-vlr-007-ref.xht == css-writing-modes/normal-flow-overconstrained-vlr-005.xht css-writing-modes/abs-pos-non-replaced-vlr-013-ref.xht == css-writing-modes/normal-flow-overconstrained-vrl-002.xht css-writing-modes/abs-pos-non-replaced-vrl-006-ref.xht @@ -890,32 +890,32 @@ fails == css-writing-modes/line-box-height-vrl-012.xht css-writing-modes/line-bo == css-writing-modes/overconstrained-rel-pos-rtl-left-right-vrl-008.xht css-writing-modes/overconstrained-rel-pos-rtl-left-right-vrl-008-ref.xht == css-writing-modes/overconstrained-rel-pos-rtl-top-bottom-vlr-007.xht css-writing-modes/overconstrained-rel-pos-rtl-top-bottom-vlr-007-ref.xht == css-writing-modes/overconstrained-rel-pos-rtl-top-bottom-vrl-006.xht css-writing-modes/overconstrained-rel-pos-rtl-top-bottom-vrl-006-ref.xht -== css-writing-modes/padding-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/padding-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vlr-007.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-margin-vrl-006.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vlr-007.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht -== css-writing-modes/percent-padding-vrl-006.xht css-writing-modes/margin-vrl-002-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-slr-023.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-slr-029.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-srl-022.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-srl-028.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vlr-003.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vlr-005.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vlr-007.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vlr-009.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vrl-002.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vrl-004.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vrl-006.xht css-writing-modes/block-flow-direction-001-ref.xht -fuzzy-if(OSX||winWidget,110,1200) == css-writing-modes/row-progression-vrl-008.xht css-writing-modes/block-flow-direction-001-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/padding-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/padding-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vlr-007.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-margin-vrl-006.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vlr-003.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vlr-005.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vlr-007.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vrl-002.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vrl-004.xht css-writing-modes/margin-vrl-002-ref.xht +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/percent-padding-vrl-006.xht css-writing-modes/margin-vrl-002-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-slr-023.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-slr-029.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-srl-022.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-srl-028.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-003.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-005.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-007.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vlr-009.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-002.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-004.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-006.xht css-writing-modes/block-flow-direction-001-ref.xht +fuzzy-if(OSX||winWidget,110,1200) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/row-progression-vrl-008.xht css-writing-modes/block-flow-direction-001-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-001.xht css-writing-modes/sizing-orthog-htb-in-vlr-001-ref.xht fails-if(Android) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == css-writing-modes/sizing-orthog-htb-in-vlr-003.xht css-writing-modes/sizing-orthog-htb-in-vlr-003-ref.xht == css-writing-modes/sizing-orthog-htb-in-vlr-004.xht css-writing-modes/sizing-orthog-htb-in-vlr-004-ref.xht diff --git a/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list b/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list index 4977b7f2b8e9..d85ef97bb2ac 100644 --- a/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list +++ b/layout/reftests/w3c-css/submitted/counter-styles-3/reftest.list @@ -1,4 +1,4 @@ -== system-cyclic.html system-cyclic-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == system-cyclic.html system-cyclic-ref.html # Bug 1392106 == system-fixed.html system-fixed-ref.html == system-symbolic.html system-symbolic-ref.html fails-if(webrender&&cocoaWidget) == system-alphabetic.html system-alphabetic-ref.html @@ -26,10 +26,10 @@ fuzzy-if(webrender,15,8) == descriptor-suffix-invalid.html descriptor-suffix-i == descriptor-pad-invalid.html descriptor-pad-invalid-ref.html == descriptor-fallback-invalid.html descriptor-fallback-invalid-ref.html == descriptor-symbols-invalid.html descriptor-symbols-invalid-ref.html -== name-case-sensitivity.html name-case-sensitivity-ref.html -fails-if(webrender&&cocoaWidget) == dependent-builtin.html dependent-builtin-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == name-case-sensitivity.html name-case-sensitivity-ref.html # Bug 1392106 +fails-if(webrender&&cocoaWidget) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == dependent-builtin.html dependent-builtin-ref.html # Bug 1392106 == redefine-builtin.html redefine-builtin-ref.html -== redefine-attr-mapping.html redefine-attr-mapping-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == redefine-attr-mapping.html redefine-attr-mapping-ref.html # Bug 1392106 == disclosure-styles.html disclosure-styles-ref.html == symbols-function.html symbols-function-ref.html == symbols-function-invalid.html symbols-function-invalid-ref.html diff --git a/layout/reftests/writing-mode/reftest.list b/layout/reftests/writing-mode/reftest.list index 473cd6de33b8..8b5110c8c068 100644 --- a/layout/reftests/writing-mode/reftest.list +++ b/layout/reftests/writing-mode/reftest.list @@ -24,8 +24,8 @@ fuzzy-if(azureSkia,255,2700) == 1090168-3.html 1090168-3-ref.html # bug 1230357 == 1094914-1b.html 1094914-1-ref.html == 1096224-1a.html 1096224-1-ref.html == 1096224-1b.html 1096224-1-ref.html -fails == 1102175-1a.html 1102175-1-ref.html -== 1102175-1b.html 1102175-1-ref.html +fails random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1102175-1a.html 1102175-1-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1102175-1b.html 1102175-1-ref.html # Bug 1392106 == 1103613-1.html 1103613-1-ref.html == 1105268-1-min-max-dimensions.html 1105268-1-min-max-dimensions-ref.html == 1105268-2-min-max-dimensions.html 1105268-2-min-max-dimensions-ref.html @@ -142,8 +142,8 @@ random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1158549-1-vertical-block == 1163238-orthogonal-auto-margins.html 1163238-orthogonal-auto-margins-ref.html == 1174450-intrinsic-sizing.html 1174450-intrinsic-sizing-ref.html skip-if(winWidget&&/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html # bug 1442637 -== 1188061-1-nsChangeHint_ClearAncestorIntrinsics.html 1188061-1-nsChangeHint_ClearAncestorIntrinsics-ref.html -== 1188061-2-nsChangeHint_UpdateComputedBSize.html 1188061-2-nsChangeHint_UpdateComputedBSize-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1188061-1-nsChangeHint_ClearAncestorIntrinsics.html 1188061-1-nsChangeHint_ClearAncestorIntrinsics-ref.html # Bug 1392106 +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1188061-2-nsChangeHint_UpdateComputedBSize.html 1188061-2-nsChangeHint_UpdateComputedBSize-ref.html # Bug 1392106 # tests involving sideways-lr mode == 1193519-sideways-lr-1.html 1193519-sideways-lr-1-ref.html diff --git a/parser/htmlparser/tests/reftest/reftest.list b/parser/htmlparser/tests/reftest/reftest.list index d2146060f772..9f35f5b41eb2 100644 --- a/parser/htmlparser/tests/reftest/reftest.list +++ b/parser/htmlparser/tests/reftest/reftest.list @@ -16,7 +16,7 @@ fuzzy-if(skiaContent,1,5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) = fuzzy-if(skiaContent,2,3) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-4.html bug659763-4-ref.html # Bug 1392106 fuzzy-if(skiaContent,1,5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-5.html bug659763-5-ref.html # Bug 1392106 fuzzy-if(skiaContent,1,5) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == bug659763-6.html bug659763-6-ref.html # Bug 1392106 -== view-source:bug673094-1.html view-source:bug673094-1-ref.html +random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == view-source:bug673094-1.html view-source:bug673094-1-ref.html # Bug 1392106 == bug696651-1.html bug696651-1-ref.html == bug696651-2.html bug696651-2-ref.html == view-source:bug700260-1.html view-source:bug700260-1-ref.html From 50afa7ac48007ca203f03905116e87f2019f82c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 1 Jun 2018 16:13:15 +0200 Subject: [PATCH 026/116] Bug 1466008: followup: set the rule type in the custom properties code, since we use it. r=me on a CLOSED TREE Though I think it may be slightly fishy if used in, e.g., a @keyframes block. For our purposes right now it doesn't make a difference, I think. MozReview-Commit-ID: A7VCTOqaIuB --- servo/components/style/properties/properties.mako.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/servo/components/style/properties/properties.mako.rs b/servo/components/style/properties/properties.mako.rs index 9ce7d3dfc38c..b7bc96973b38 100644 --- a/servo/components/style/properties/properties.mako.rs +++ b/servo/components/style/properties/properties.mako.rs @@ -1422,10 +1422,12 @@ impl UnparsedValue { .and_then(|css| { // As of this writing, only the base URL is used for property // values. + // + // FIXME(emilio): These bits are slightly fishy. let context = ParserContext::new( Origin::Author, &self.url_data, - None, + Some(CssRuleType::Style), ParsingMode::DEFAULT, quirks_mode, ); From 527f952a0bf1691c62d0428ed1dff2c4ebdd6d7c Mon Sep 17 00:00:00 2001 From: David Major Date: Fri, 1 Jun 2018 10:18:27 -0400 Subject: [PATCH 027/116] Bug 1360120: Promote win64-asan builds and tests to tier 2. r=dustin I've deliberately left as tier-3 the following tests: - gtest (perma-OOM, likely from ASan malloc-meddling) - xpcshell (builds need to be signed plus other failures too) --HG-- extra : rebase_source : 812bf0de11e91c4e952cb5da9163241bd9386246 --- taskcluster/ci/build/windows.yml | 4 ++-- taskcluster/ci/test/compiled.yml | 14 ++------------ taskcluster/ci/test/firefox-ui.yml | 9 +-------- taskcluster/ci/test/marionette.yml | 5 ----- taskcluster/ci/test/misc.yml | 15 +++------------ taskcluster/ci/test/mochitest.yml | 27 --------------------------- taskcluster/ci/test/reftest.yml | 7 ------- taskcluster/ci/test/web-platform.yml | 10 ++-------- 8 files changed, 10 insertions(+), 81 deletions(-) diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index cc904041ff1d..bc7ec10414c4 100755 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -576,7 +576,7 @@ win64-asan/debug: treeherder: platform: windows2012-64/asan symbol: Bd - tier: 3 + tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 worker: max-run-time: 7200 @@ -606,7 +606,7 @@ win64-asan/opt: treeherder: platform: windows2012-64/asan symbol: Bo - tier: 3 + tier: 2 worker-type: aws-provisioner-v1/gecko-{level}-b-win2012 worker: max-run-time: 7200 diff --git a/taskcluster/ci/test/compiled.yml b/taskcluster/ci/test/compiled.yml index d52e8b666427..37c14bbf8bc8 100644 --- a/taskcluster/ci/test/compiled.yml +++ b/taskcluster/ci/test/compiled.yml @@ -26,14 +26,7 @@ cppunit: by-test-platform: android.*: xlarge default: default - run-on-projects: - by-test-platform: - windows10-64-asan/opt: [] # as an exception to windows.* - default: built-projects - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default + run-on-projects: built-projects gtest: description: "GTests run" @@ -44,6 +37,7 @@ gtest: by-test-platform: windows.*-pgo/.*: [] # permafails on pgo windows.*-nightly/.*: [] # permafails on nightly too + windows10-64-asan/opt: [] # permafails on asan too .*-devedition/.*: [] # don't run on devedition default: built-projects tier: @@ -80,7 +74,3 @@ jittest: windows.*: false macosx.*: false default: true - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default diff --git a/taskcluster/ci/test/firefox-ui.yml b/taskcluster/ci/test/firefox-ui.yml index 7c70ff33562e..afa6f873f7c1 100644 --- a/taskcluster/ci/test/firefox-ui.yml +++ b/taskcluster/ci/test/firefox-ui.yml @@ -21,10 +21,6 @@ firefox-ui-functional-local: extra-options: - "--tag" - "local" - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default firefox-ui-functional-remote: description: "Firefox-ui-tests functional run" @@ -34,7 +30,4 @@ firefox-ui-functional-remote: extra-options: - "--tag" - "remote" - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 diff --git a/taskcluster/ci/test/marionette.yml b/taskcluster/ci/test/marionette.yml index 4c5217c322f8..b9f4130a3e3e 100644 --- a/taskcluster/ci/test/marionette.yml +++ b/taskcluster/ci/test/marionette.yml @@ -33,7 +33,6 @@ marionette: tier: by-test-platform: android.*: 2 - windows10-64-asan.*: 3 default: default chunks: by-test-platform: @@ -48,7 +47,3 @@ marionette-headless: mozharness: extra-options: - --headless - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default diff --git a/taskcluster/ci/test/misc.yml b/taskcluster/ci/test/misc.yml index 7e1369bb4ea8..b86c5ffb8d6e 100644 --- a/taskcluster/ci/test/misc.yml +++ b/taskcluster/ci/test/misc.yml @@ -102,10 +102,7 @@ test-verify: .*-ccov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 mozharness: script: by-test-platform: @@ -144,10 +141,7 @@ test-verify-gpu: .*-ccov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 mozharness: script: by-test-platform: @@ -182,10 +176,7 @@ test-coverage: # only run on mozilla-central and try. .*-ccov/.*: ['mozilla-central', 'try'] default: [] - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 mozharness: script: by-test-platform: diff --git a/taskcluster/ci/test/mochitest.yml b/taskcluster/ci/test/mochitest.yml index 2835c34b70d2..0555fd0ec4e9 100644 --- a/taskcluster/ci/test/mochitest.yml +++ b/taskcluster/ci/test/mochitest.yml @@ -67,10 +67,6 @@ mochitest: android.*: 7200 default: 5400 allow-software-gl-layers: false - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default mozharness: mochitest-flavor: plain extra-options: @@ -92,10 +88,6 @@ mochitest-a11y: run-on-projects: built-projects mozharness: mochitest-flavor: a11y - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default mochitest-browser-chrome: description: "Mochitest browser-chrome run" @@ -125,10 +117,6 @@ mochitest-browser-chrome: linux64-jsdcov/opt: xlarge default: default allow-software-gl-layers: false - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default browser-instrumentation: description: "Extra instrumentation for a browser-chrome run (XUL, XBL, etc)" @@ -194,10 +182,6 @@ mochitest-chrome: by-test-platform: android.*: false default: true - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default mochitest-clipboard: description: "Mochitest clipboard run" @@ -222,10 +206,6 @@ mochitest-clipboard: - --test-suite=mochitest-plain-clipboard default: - --mochitest-suite=plain-clipboard,chrome-clipboard,browser-chrome-clipboard - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default mochitest-devtools-chrome: description: "Mochitest devtools-chrome run" @@ -256,10 +236,6 @@ mochitest-devtools-chrome: default: default # Bug 1296086: high number of intermittents observed with software GL and large instances allow-software-gl-layers: false - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default mochitest-gpu: description: "Mochitest GPU run" @@ -288,7 +264,6 @@ mochitest-gpu: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default mochitest-media: @@ -326,7 +301,6 @@ mochitest-media: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default mochitest-plain-headless: @@ -404,5 +378,4 @@ mochitest-webgl: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default diff --git a/taskcluster/ci/test/reftest.yml b/taskcluster/ci/test/reftest.yml index 43c78671a27f..eccc2ae53c5a 100644 --- a/taskcluster/ci/test/reftest.yml +++ b/taskcluster/ci/test/reftest.yml @@ -50,7 +50,6 @@ crashtest: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default jsreftest: @@ -83,7 +82,6 @@ jsreftest: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default reftest: @@ -129,7 +127,6 @@ reftest: tier: by-test-platform: linux64-qr/.*: 1 - windows10-64-asan.*: 3 default: default reftest-gpu: @@ -171,7 +168,3 @@ reftest-no-accel: windows10-64.*/opt: false macosx.*: false default: true - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: default diff --git a/taskcluster/ci/test/web-platform.yml b/taskcluster/ci/test/web-platform.yml index 1be0260f7044..7e45a1325b2d 100644 --- a/taskcluster/ci/test/web-platform.yml +++ b/taskcluster/ci/test/web-platform.yml @@ -145,10 +145,7 @@ test-verify-wpt: .*-ccov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 mozharness: extra-options: - --verify @@ -163,10 +160,7 @@ test-coverage-wpt: # only run on mozilla-central and try. .*-ccov/.*: ['mozilla-central', 'try'] default: [] - tier: - by-test-platform: - windows10-64-asan.*: 3 - default: 2 + tier: 2 mozharness: extra-options: - --per-test-coverage From 5c50ac6e3463b05a73d8a05104e4ab2ce64d149d Mon Sep 17 00:00:00 2001 From: David Major Date: Fri, 1 Jun 2018 10:18:47 -0400 Subject: [PATCH 028/116] Bug 1360120: Run Win64 ASan builds and tests on trunk and try. r=coop --HG-- extra : rebase_source : 29f193cf282b490b44e45aa9bf31435daabe82f2 --- taskcluster/ci/build/windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index bc7ec10414c4..5c83b822b5bf 100755 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -592,7 +592,7 @@ win64-asan/debug: - builds/taskcluster_base_windows.py - builds/taskcluster_base_win64.py - builds/taskcluster_sub_win64/asan_debug.py - run-on-projects: [] + run-on-projects: ['trunk', 'try'] toolchains: - win64-clang-cl - win64-rust @@ -622,7 +622,7 @@ win64-asan/opt: - builds/taskcluster_base_windows.py - builds/taskcluster_base_win64.py - builds/taskcluster_sub_win64/asan_opt.py - run-on-projects: [] + run-on-projects: ['trunk', 'try'] toolchains: - win64-clang-cl - win64-rust From 11348779bc1d88ddb621c9c4667c9fb1496a160a Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Fri, 1 Jun 2018 11:14:59 +0100 Subject: [PATCH 029/116] Bug 1457719 - Part 1 - Restore "scrollbox.css" as a XBL stylesheet. r=dao MozReview-Commit-ID: 9StACNxSbX2 --HG-- extra : rebase_source : 656340aade40d877e09444db3ffa0ddb756dcdae --- toolkit/content/components.css | 1 - toolkit/content/widgets/scrollbox.xml | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/toolkit/content/components.css b/toolkit/content/components.css index 83d9b80edb8e..2373f6953ba2 100644 --- a/toolkit/content/components.css +++ b/toolkit/content/components.css @@ -10,6 +10,5 @@ @import url("chrome://global/skin/groupbox.css"); @import url("chrome://global/skin/menu.css"); @import url("chrome://global/skin/menulist.css"); -@import url("chrome://global/skin/scrollbox.css"); @import url("chrome://global/skin/toolbar.css"); @import url("chrome://global/skin/splitter.css"); diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml index c745676b6d6a..b85a7d3d0314 100644 --- a/toolkit/content/widgets/scrollbox.xml +++ b/toolkit/content/widgets/scrollbox.xml @@ -27,6 +27,10 @@ + + + + + + + + From 47fe75160ecb7ea772a10d139c9a7c474c3973b1 Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Fri, 1 Jun 2018 11:15:13 +0100 Subject: [PATCH 030/116] Bug 1457719 - Part 2 - Disable the reftest for "arrowscrollbox" scrolling for timing issues. rs=dao MozReview-Commit-ID: ICEyF1zpaLn --HG-- extra : rebase_source : 672f94e2b638e7112c9b6bbe60b1c6dd9d6950b3 --- layout/reftests/bugs/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index e046a89f84f9..5017c4729d22 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1410,7 +1410,7 @@ fuzzy-if(Android,5,2800) == 506481-1.html 506481-1-ref.html == 507762-2.html 507762-2-ref.html == 507762-3.html 507762-1-ref.html == 507762-4.html 507762-2-ref.html -random-if(cocoaWidget||winWidget) == 508816-1.xul 508816-1-ref.xul # Bug 631982 and bug 1375012 +random == 508816-1.xul 508816-1-ref.xul # Bug 1375012 == 508816-2.html 508816-2-ref.html skip-if(isDebugBuild) == 508908-1.xul 508908-1-ref.xul == 508919-1.xhtml 508919-1-ref.xhtml From ff86c8779dc6f1fcc59f059af3d76af177b5e0c7 Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Fri, 1 Jun 2018 11:15:36 +0100 Subject: [PATCH 031/116] Bug 1457719 - Part 3 - Replace "autorepeatbutton" with "toolbarbutton" in the base "arrowscrollbox" binding. r=dao This aligns the markup of the base "arrowscrollbox" binding with the "clicktoscroll" derived binding, while still keeping different event handlers. MozReview-Commit-ID: 9eYt1kyjgP9 --HG-- extra : rebase_source : 16600f0916ac4188ceaf8dff61fb61021cc8da5a --- .../shared/customizableui/panelUI.inc.css | 12 +--- toolkit/content/widgets/scrollbox.xml | 59 ++++++++++++++----- toolkit/themes/linux/global/scrollbox.css | 9 ++- toolkit/themes/osx/global/global.css | 14 +++-- toolkit/themes/osx/global/scrollbox.css | 20 ++----- toolkit/themes/windows/global/scrollbox.css | 21 ++----- 6 files changed, 69 insertions(+), 66 deletions(-) diff --git a/browser/themes/shared/customizableui/panelUI.inc.css b/browser/themes/shared/customizableui/panelUI.inc.css index d19131033a02..1cd41225766d 100644 --- a/browser/themes/shared/customizableui/panelUI.inc.css +++ b/browser/themes/shared/customizableui/panelUI.inc.css @@ -194,14 +194,6 @@ panelview { -moz-box-flex: 1; } -#appMenu-popup > arrowscrollbox > autorepeatbutton { - display: none; -} - -#appMenu-popup > arrowscrollbox > scrollbox { - overflow: visible; -} - #appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent, panel[photon] > .panel-arrowcontainer > .panel-arrowcontent { overflow: hidden; @@ -1109,8 +1101,8 @@ menuitem.panel-subview-footer@menuStateActive@, margin-inline-end: 3px; } -#BMB_bookmarksPopup .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-up, -#BMB_bookmarksPopup .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-down { +#BMB_bookmarksPopup .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .scrollbutton-up, +#BMB_bookmarksPopup .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .scrollbutton-down { -moz-appearance: none; margin-top: 0; margin-bottom: 0; diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml index b85a7d3d0314..74ab3c1abfac 100644 --- a/toolkit/content/widgets/scrollbox.xml +++ b/toolkit/content/widgets/scrollbox.xml @@ -32,10 +32,11 @@ - + - + @@ -63,6 +65,14 @@ this._updateScrollButtonsDisabledState(); ]]> + + document.getAnonymousElementByAttribute(this, "anonid", "scrollbox"); @@ -320,16 +330,35 @@ ]]> - - + + this.scrollByPixels(this.scrollIncrement * index); + + // Use the same REPEAT_DELAY as "nsRepeatService.h". + let scrollDelay = /Mac/.test(navigator.platform) ? 25 : 50; + + this._scrollTimer.initWithCallback(callback, scrollDelay, + Ci.nsITimer.TYPE_REPEATING_SLACK); + callback(); + ]]> + + + + + diff --git a/toolkit/themes/linux/global/scrollbox.css b/toolkit/themes/linux/global/scrollbox.css index 90cbc8652379..18ca35577f07 100644 --- a/toolkit/themes/linux/global/scrollbox.css +++ b/toolkit/themes/linux/global/scrollbox.css @@ -4,22 +4,18 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); -.autorepeatbutton-up > .autorepeatbutton-icon, .scrollbutton-up > .toolbarbutton-icon { -moz-appearance: button-arrow-up; } -.autorepeatbutton-down > .autorepeatbutton-icon, .scrollbutton-down > .toolbarbutton-icon { -moz-appearance: button-arrow-down; } -.autorepeatbutton-up[orient="horizontal"] > .autorepeatbutton-icon, .scrollbutton-up[orient="horizontal"] > .toolbarbutton-icon { -moz-appearance: button-arrow-previous; } -.autorepeatbutton-down[orient="horizontal"] > .autorepeatbutton-icon, .scrollbutton-down[orient="horizontal"] > .toolbarbutton-icon { -moz-appearance: button-arrow-next; } @@ -28,6 +24,9 @@ display: none; } -autorepeatbutton { +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-up, +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-down { + -moz-appearance: none; border: 1px solid ThreeDShadow; + padding: 0; } diff --git a/toolkit/themes/osx/global/global.css b/toolkit/themes/osx/global/global.css index a6e55a0b40b6..964df89153bc 100644 --- a/toolkit/themes/osx/global/global.css +++ b/toolkit/themes/osx/global/global.css @@ -280,7 +280,8 @@ popupnotificationcontent { /* autorepeatbuttons in menus */ -.popup-internal-box > autorepeatbutton { +.popup-internal-box > .scrollbutton-up, +.popup-internal-box > .scrollbutton-down { height: 15px; position: relative; list-style-image: none; @@ -296,25 +297,26 @@ popupnotificationcontent { -moz-appearance: menuitem; } -.popup-internal-box > .autorepeatbutton-up { +.popup-internal-box > .scrollbutton-up { padding-top: 1px; /* 4px padding-top from the .popup-internal-box. */ margin-bottom: -15px; } -.popup-internal-box > .autorepeatbutton-up > .autorepeatbutton-icon { +.popup-internal-box > .scrollbutton-up > .toolbarbutton-icon { -moz-appearance: button-arrow-up; } -.popup-internal-box > .autorepeatbutton-down { +.popup-internal-box > .scrollbutton-down { padding-top: 5px; margin-top: -15px; } -.popup-internal-box > .autorepeatbutton-down > .autorepeatbutton-icon { +.popup-internal-box > .scrollbutton-down > .toolbarbutton-icon { -moz-appearance: button-arrow-down; } -.popup-internal-box > autorepeatbutton[disabled="true"] { +.popup-internal-box > .scrollbutton-up[disabled="true"], +.popup-internal-box > .scrollbutton-down[disabled="true"] { visibility: collapse; } diff --git a/toolkit/themes/osx/global/scrollbox.css b/toolkit/themes/osx/global/scrollbox.css index c9b727669880..e20456ffcd0c 100644 --- a/toolkit/themes/osx/global/scrollbox.css +++ b/toolkit/themes/osx/global/scrollbox.css @@ -5,53 +5,45 @@ @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* Horizontal enabled */ -.autorepeatbutton-up[orient="horizontal"], .scrollbutton-up[orient="horizontal"] { list-style-image: url("chrome://global/skin/arrow/arrow-lft-sharp.gif"); -moz-image-region: auto; /* cut off inheritance */ } - -.autorepeatbutton-down[orient="horizontal"], + .scrollbutton-down[orient="horizontal"] { list-style-image: url("chrome://global/skin/arrow/arrow-rit-sharp.gif"); -moz-image-region: auto; /* cut off inheritance */ } /* Horizontal disabled */ -.autorepeatbutton-up[orient="horizontal"][disabled="true"], .scrollbutton-up[orient="horizontal"][disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } - -.autorepeatbutton-down[orient="horizontal"][disabled="true"], + .scrollbutton-down[orient="horizontal"][disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } /* Vertical enabled */ -.autorepeatbutton-up:not([orient="horizontal"]), -.scrollbutton-up { +.scrollbutton-up:not([orient="horizontal"]) { list-style-image: url("chrome://global/skin/arrow/arrow-up-sharp.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down:not([orient="horizontal"]), -.scrollbutton-down { +.scrollbutton-down:not([orient="horizontal"]) { list-style-image: url("chrome://global/skin/arrow/arrow-dn-sharp.gif"); -moz-image-region: auto; /* cut off inheritance */ } /* Vertical disabled */ -.autorepeatbutton-up[disabled="true"]:not([orient="horizontal"]), -.scrollbutton-up[disabled="true"] { +.scrollbutton-up[disabled="true"]:not([orient="horizontal"]) { list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down[disabled="true"]:not([orient="horizontal"]), -.scrollbutton-down[disabled="true"] { +.scrollbutton-down[disabled="true"]:not([orient="horizontal"]) { list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } diff --git a/toolkit/themes/windows/global/scrollbox.css b/toolkit/themes/windows/global/scrollbox.css index b7a6f9987cf9..94a75b2e6f90 100644 --- a/toolkit/themes/windows/global/scrollbox.css +++ b/toolkit/themes/windows/global/scrollbox.css @@ -9,16 +9,12 @@ */ /* Horizontal enabled */ -.autorepeatbutton-up[orient="horizontal"], -.autorepeatbutton-down:-moz-locale-dir(rtl)[orient="horizontal"], .scrollbutton-up[orient="horizontal"], .scrollbutton-down:-moz-locale-dir(rtl)[orient="horizontal"] { list-style-image: url("chrome://global/skin/arrow/arrow-lft.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down[orient="horizontal"], -.autorepeatbutton-up:-moz-locale-dir(rtl)[orient="horizontal"], .scrollbutton-down[orient="horizontal"], .scrollbutton-up:-moz-locale-dir(rtl)[orient="horizontal"] { list-style-image: url("chrome://global/skin/arrow/arrow-rit.gif"); @@ -26,16 +22,12 @@ } /* Horizontal disabled */ -.autorepeatbutton-up[orient="horizontal"][disabled="true"], -.autorepeatbutton-down:-moz-locale-dir(rtl)[orient="horizontal"][disabled="true"], .scrollbutton-up[orient="horizontal"][disabled="true"], .scrollbutton-down:-moz-locale-dir(rtl)[orient="horizontal"][disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-lft-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down[orient="horizontal"][disabled="true"], -.autorepeatbutton-up:-moz-locale-dir(rtl)[orient="horizontal"][disabled="true"], .scrollbutton-down[orient="horizontal"][disabled="true"], .scrollbutton-up:-moz-locale-dir(rtl)[orient="horizontal"][disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-rit-dis.gif"); @@ -43,26 +35,22 @@ } /* Vertical enabled */ -.autorepeatbutton-up, .scrollbutton-up { list-style-image: url("chrome://global/skin/arrow/arrow-up.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down, .scrollbutton-down { list-style-image: url("chrome://global/skin/arrow/arrow-dn.gif"); -moz-image-region: auto; /* cut off inheritance */ } /* Vertical disabled */ -.autorepeatbutton-up[disabled="true"], .scrollbutton-up[disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-up-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ } -.autorepeatbutton-down[disabled="true"], .scrollbutton-down[disabled="true"] { list-style-image: url("chrome://global/skin/arrow/arrow-dn-dis.gif"); -moz-image-region: auto; /* cut off inheritance */ @@ -73,7 +61,6 @@ display: none; } -autorepeatbutton, .scrollbutton-up, .scrollbutton-down { -moz-box-align: center; @@ -84,13 +71,15 @@ autorepeatbutton, margin-inline-end: 2px; } -autorepeatbutton { +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-up, +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-down { + -moz-appearance: none; border: 1px solid transparent; padding: 1px; } -autorepeatbutton:not([disabled="true"]):hover, -autorepeatbutton:not([disabled="true"]):hover:active { +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-up:not([disabled="true"]):hover, +arrowscrollbox:not([clicktoscroll="true"]) > .scrollbutton-down:not([disabled="true"]):hover { margin: 1px; border: 1px inset ThreeDFace; padding-top: 2px; From 61cbbdb92c944d5533ac8e217300e20d1e846ad4 Mon Sep 17 00:00:00 2001 From: Paolo Amadini Date: Fri, 1 Jun 2018 11:15:56 +0100 Subject: [PATCH 032/116] Bug 1457719 - Part 4 - Remove the "autorepeatbutton" element. r=bz The DoMouseClick helper is also removed because no other caller can now pass a null aEvent. Other MouseClicked implementations are also updated since aEvent cannot be null, which was already the case. MozReview-Commit-ID: 3bTJ6cZW9ZA --HG-- extra : rebase_source : ae1bafe7144f6f428e2ef4e7047d5c64e0a19e8c --- dom/xbl/nsXBLPrototypeBinding.cpp | 2 +- layout/base/PositionedEventTargeting.cpp | 1 - layout/base/nsCSSFrameConstructor.cpp | 4 - layout/generic/nsFrameIdList.h | 1 - layout/xul/crashtests/460900-1.xul | 3 - layout/xul/crashtests/crashtests.list | 1 - layout/xul/moz.build | 1 - layout/xul/nsButtonBoxFrame.cpp | 41 ++--- layout/xul/nsButtonBoxFrame.h | 8 +- layout/xul/nsResizerFrame.cpp | 22 +-- layout/xul/nsScrollBoxFrame.cpp | 184 ----------------------- layout/xul/nsScrollbarButtonFrame.cpp | 7 - layout/xul/nsScrollbarButtonFrame.h | 2 - layout/xul/nsTitleBarFrame.cpp | 22 +-- toolkit/content/widgets/scrollbox.xml | 10 -- toolkit/content/xul.css | 4 - xpcom/ds/nsGkAtomList.h | 1 - 17 files changed, 23 insertions(+), 291 deletions(-) delete mode 100644 layout/xul/crashtests/460900-1.xul delete mode 100644 layout/xul/nsScrollBoxFrame.cpp diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp index 47c9b8f13317..426eaa18d269 100644 --- a/dom/xbl/nsXBLPrototypeBinding.cpp +++ b/dom/xbl/nsXBLPrototypeBinding.cpp @@ -1547,7 +1547,7 @@ nsXBLPrototypeBinding::WriteNamespace(nsIObjectOutputStream* aStream, bool CheckTagNameWhiteList(int32_t aNameSpaceID, nsAtom *aTagName) { static Element::AttrValuesArray kValidXULTagNames[] = { - &nsGkAtoms::autorepeatbutton, &nsGkAtoms::box, &nsGkAtoms::browser, + &nsGkAtoms::box, &nsGkAtoms::browser, &nsGkAtoms::button, &nsGkAtoms::hbox, &nsGkAtoms::image, &nsGkAtoms::menu, &nsGkAtoms::menubar, &nsGkAtoms::menuitem, &nsGkAtoms::menupopup, &nsGkAtoms::row, &nsGkAtoms::slider, &nsGkAtoms::spacer, diff --git a/layout/base/PositionedEventTargeting.cpp b/layout/base/PositionedEventTargeting.cpp index f6b768a3b285..2cde89e50f99 100644 --- a/layout/base/PositionedEventTargeting.cpp +++ b/layout/base/PositionedEventTargeting.cpp @@ -237,7 +237,6 @@ GetClickableAncestor(nsIFrame* aFrame, nsAtom* stopAt = nullptr, nsAutoString* a if (content->IsAnyOfXULElements(nsGkAtoms::button, nsGkAtoms::checkbox, nsGkAtoms::radio, - nsGkAtoms::autorepeatbutton, nsGkAtoms::menu, nsGkAtoms::menubutton, nsGkAtoms::menuitem, diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 53cff6a89c84..2358e6d5e889 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -234,9 +234,6 @@ static FrameCtorDebugFlags gFlags[] = { //------------------------------------------------------------------ -nsIFrame* -NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle); - nsContainerFrame* NS_NewRootBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle); @@ -4292,7 +4289,6 @@ nsCSSFrameConstructor::FindXULTagData(Element* aElement, SCROLLABLE_XUL_CREATE(thumb, NS_NewButtonBoxFrame), SCROLLABLE_XUL_CREATE(checkbox, NS_NewButtonBoxFrame), SCROLLABLE_XUL_CREATE(radio, NS_NewButtonBoxFrame), - SCROLLABLE_XUL_CREATE(autorepeatbutton, NS_NewAutoRepeatBoxFrame), SCROLLABLE_XUL_CREATE(titlebar, NS_NewTitleBarFrame), SCROLLABLE_XUL_CREATE(resizer, NS_NewResizerFrame), SCROLLABLE_XUL_CREATE(toolbarpaletteitem, NS_NewBoxFrame), diff --git a/layout/generic/nsFrameIdList.h b/layout/generic/nsFrameIdList.h index f82c727742d5..a42138b5ca8c 100644 --- a/layout/generic/nsFrameIdList.h +++ b/layout/generic/nsFrameIdList.h @@ -6,7 +6,6 @@ FRAME_ID(BRFrame, Br, Leaf) FRAME_ID(DetailsFrame, Details, NotLeaf) -FRAME_ID(nsAutoRepeatBoxFrame, Box, NotLeaf) FRAME_ID(nsBCTableCellFrame, BCTableCell, NotLeaf) FRAME_ID(nsBackdropFrame, Backdrop, Leaf) FRAME_ID(nsBlockFrame, Block, NotLeaf) diff --git a/layout/xul/crashtests/460900-1.xul b/layout/xul/crashtests/460900-1.xul deleted file mode 100644 index bff7c5c36b35..000000000000 --- a/layout/xul/crashtests/460900-1.xul +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/layout/xul/crashtests/crashtests.list b/layout/xul/crashtests/crashtests.list index 45b0be960950..156acc360f90 100644 --- a/layout/xul/crashtests/crashtests.list +++ b/layout/xul/crashtests/crashtests.list @@ -74,7 +74,6 @@ load 432068-2.xul load 433296-1.xul load 433429.xul load 452185.html -load 460900-1.xul load 464149-1.xul asserts(0-1) load 464407-1.xhtml # Bugs 450974, 1267054, 718883 load 467080.xul diff --git a/layout/xul/moz.build b/layout/xul/moz.build index d9bd934c2912..9700a78c8868 100644 --- a/layout/xul/moz.build +++ b/layout/xul/moz.build @@ -49,7 +49,6 @@ UNIFIED_SOURCES += [ 'nsRootBoxFrame.cpp', 'nsScrollbarButtonFrame.cpp', 'nsScrollbarFrame.cpp', - 'nsScrollBoxFrame.cpp', 'nsSliderFrame.cpp', 'nsSprocketLayout.cpp', 'nsStackFrame.cpp', diff --git a/layout/xul/nsButtonBoxFrame.cpp b/layout/xul/nsButtonBoxFrame.cpp index b73d00c30ea7..fd27bc3f82b8 100644 --- a/layout/xul/nsButtonBoxFrame.cpp +++ b/layout/xul/nsButtonBoxFrame.cpp @@ -197,40 +197,25 @@ nsButtonBoxFrame::Blurred() } void -nsButtonBoxFrame::DoMouseClick(WidgetGUIEvent* aEvent, bool aTrustEvent) +nsButtonBoxFrame::MouseClicked(WidgetGUIEvent* aEvent) { // Don't execute if we're disabled. if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled, nsGkAtoms::_true, eCaseMatters)) return; - // Execute the oncommand event handler. - bool isShift = false; - bool isControl = false; - bool isAlt = false; - bool isMeta = false; - uint16_t inputSource = MouseEventBinding::MOZ_SOURCE_UNKNOWN; - - if(aEvent) { - WidgetInputEvent* inputEvent = aEvent->AsInputEvent(); - isShift = inputEvent->IsShift(); - isControl = inputEvent->IsControl(); - isAlt = inputEvent->IsAlt(); - isMeta = inputEvent->IsMeta(); - - WidgetMouseEventBase* mouseEvent = aEvent->AsMouseEventBase(); - if (mouseEvent) { - inputSource = mouseEvent->inputSource; - } - } - // Have the content handle the event, propagating it according to normal DOM rules. nsCOMPtr shell = PresContext()->GetPresShell(); - if (shell) { - nsContentUtils::DispatchXULCommand(mContent, - aEvent ? - aEvent->IsTrusted() : aTrustEvent, - nullptr, shell, - isControl, isAlt, isShift, isMeta, inputSource); - } + if (!shell) + return; + + // Execute the oncommand event handler. + WidgetInputEvent* inputEvent = aEvent->AsInputEvent(); + WidgetMouseEventBase* mouseEvent = aEvent->AsMouseEventBase(); + nsContentUtils::DispatchXULCommand(mContent, aEvent->IsTrusted(), nullptr, + shell, inputEvent->IsControl(), + inputEvent->IsAlt(), inputEvent->IsShift(), + inputEvent->IsMeta(), + mouseEvent ? mouseEvent->inputSource + : MouseEventBinding::MOZ_SOURCE_UNKNOWN); } diff --git a/layout/xul/nsButtonBoxFrame.h b/layout/xul/nsButtonBoxFrame.h index 4ba72291c2a4..3a546d5541fe 100644 --- a/layout/xul/nsButtonBoxFrame.h +++ b/layout/xul/nsButtonBoxFrame.h @@ -32,8 +32,7 @@ public: mozilla::WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) override; - virtual void MouseClicked(mozilla::WidgetGUIEvent* aEvent) - { DoMouseClick(aEvent, false); } + virtual void MouseClicked(mozilla::WidgetGUIEvent* aEvent); void Blurred(); @@ -43,11 +42,6 @@ public: } #endif - /** - * Our implementation of MouseClicked. - * @param aTrustEvent if true and aEvent as null, then assume the event was trusted - */ - void DoMouseClick(mozilla::WidgetGUIEvent* aEvent, bool aTrustEvent); void UpdateMouseThrough() override { AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); } private: diff --git a/layout/xul/nsResizerFrame.cpp b/layout/xul/nsResizerFrame.cpp index a82d34198fd0..a1b1d60091e9 100644 --- a/layout/xul/nsResizerFrame.cpp +++ b/layout/xul/nsResizerFrame.cpp @@ -535,23 +535,9 @@ nsResizerFrame::GetDirection() void nsResizerFrame::MouseClicked(WidgetMouseEvent* aEvent) { - bool isTrusted = false; - bool isShift = false; - bool isControl = false; - bool isAlt = false; - bool isMeta = false; - uint16_t inputSource = dom::MouseEventBinding::MOZ_SOURCE_UNKNOWN; - - if(aEvent) { - isShift = aEvent->IsShift(); - isControl = aEvent->IsControl(); - isAlt = aEvent->IsAlt(); - isMeta = aEvent->IsMeta(); - inputSource = aEvent->inputSource; - } - // Execute the oncommand event handler. - nsContentUtils::DispatchXULCommand(mContent, isTrusted, nullptr, - nullptr, isControl, isAlt, - isShift, isMeta, inputSource); + nsContentUtils::DispatchXULCommand(mContent, false, nullptr, + nullptr, aEvent->IsControl(), + aEvent->IsAlt(), aEvent->IsShift(), + aEvent->IsMeta(), aEvent->inputSource); } diff --git a/layout/xul/nsScrollBoxFrame.cpp b/layout/xul/nsScrollBoxFrame.cpp deleted file mode 100644 index 162983d56dad..000000000000 --- a/layout/xul/nsScrollBoxFrame.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=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/. */ - -#include "nsCOMPtr.h" -#include "nsPresContext.h" -#include "nsGkAtoms.h" -#include "nsButtonBoxFrame.h" -#include "nsITimer.h" -#include "nsRepeatService.h" -#include "mozilla/MouseEvents.h" -#include "nsIContent.h" - -using namespace mozilla; - -class nsAutoRepeatBoxFrame final : public nsButtonBoxFrame -{ -public: - NS_DECL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame) - - friend nsIFrame* NS_NewAutoRepeatBoxFrame(nsIPresShell* aPresShell, - ComputedStyle* aStyle); - - virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; - - virtual nsresult AttributeChanged(int32_t aNameSpaceID, - nsAtom* aAttribute, - int32_t aModType) override; - - virtual nsresult HandleEvent(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) override; - - NS_IMETHOD HandlePress(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) override; - - NS_IMETHOD HandleRelease(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) override; - -protected: - explicit nsAutoRepeatBoxFrame(ComputedStyle* aStyle): - nsButtonBoxFrame(aStyle, kClassID) {} - - void StartRepeat() { - if (IsActivatedOnHover()) { - // No initial delay on hover. - nsRepeatService::GetInstance()->Start(Notify, this, - mContent->OwnerDoc(), - NS_LITERAL_CSTRING("DoMouseClick"), - 0); - } else { - nsRepeatService::GetInstance()->Start(Notify, this, - mContent->OwnerDoc(), - NS_LITERAL_CSTRING("DoMouseClick")); - } - } - void StopRepeat() { - nsRepeatService::GetInstance()->Stop(Notify, this); - } - void Notify(); - static void Notify(void* aData) { - static_cast(aData)->Notify(); - } - - bool mTrustedEvent; - - bool IsActivatedOnHover(); -}; - -nsIFrame* -NS_NewAutoRepeatBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle) -{ - return new (aPresShell) nsAutoRepeatBoxFrame(aStyle); -} - -NS_IMPL_FRAMEARENA_HELPERS(nsAutoRepeatBoxFrame) - -nsresult -nsAutoRepeatBoxFrame::HandleEvent(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) -{ - NS_ENSURE_ARG_POINTER(aEventStatus); - if (nsEventStatus_eConsumeNoDefault == *aEventStatus) { - return NS_OK; - } - - switch(aEvent->mMessage) { - // repeat mode may be "hover" for repeating while the mouse is hovering - // over the element, otherwise repetition is done while the element is - // active (pressed). - case eMouseEnterIntoWidget: - case eMouseOver: - if (IsActivatedOnHover()) { - StartRepeat(); - mTrustedEvent = aEvent->IsTrusted(); - } - break; - - case eMouseExitFromWidget: - case eMouseOut: - // always stop on mouse exit - StopRepeat(); - // Not really necessary but do this to be safe - mTrustedEvent = false; - break; - - case eMouseClick: { - WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); - if (mouseEvent->IsLeftClickEvent()) { - // skip button frame handling to prevent click handling - return nsBoxFrame::HandleEvent(aPresContext, mouseEvent, aEventStatus); - } - break; - } - - default: - break; - } - - return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); -} - -NS_IMETHODIMP -nsAutoRepeatBoxFrame::HandlePress(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) -{ - if (!IsActivatedOnHover()) { - StartRepeat(); - mTrustedEvent = aEvent->IsTrusted(); - DoMouseClick(aEvent, mTrustedEvent); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsAutoRepeatBoxFrame::HandleRelease(nsPresContext* aPresContext, - WidgetGUIEvent* aEvent, - nsEventStatus* aEventStatus) -{ - if (!IsActivatedOnHover()) { - StopRepeat(); - } - return NS_OK; -} - -nsresult -nsAutoRepeatBoxFrame::AttributeChanged(int32_t aNameSpaceID, - nsAtom* aAttribute, - int32_t aModType) -{ - if (aAttribute == nsGkAtoms::type) { - StopRepeat(); - } - return NS_OK; -} - -void -nsAutoRepeatBoxFrame::Notify() -{ - DoMouseClick(nullptr, mTrustedEvent); -} - -void -nsAutoRepeatBoxFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) -{ - // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out - // from under you while you're in the process of scrolling. - StopRepeat(); - nsButtonBoxFrame::DestroyFrom(aDestructRoot, aPostDestroyData); -} - -bool -nsAutoRepeatBoxFrame::IsActivatedOnHover() -{ - return mContent->AsElement()->AttrValueIs( - kNameSpaceID_None, nsGkAtoms::repeat, nsGkAtoms::hover, eCaseMatters); -} diff --git a/layout/xul/nsScrollbarButtonFrame.cpp b/layout/xul/nsScrollbarButtonFrame.cpp index 12faa573bee8..122a3e170598 100644 --- a/layout/xul/nsScrollbarButtonFrame.cpp +++ b/layout/xul/nsScrollbarButtonFrame.cpp @@ -225,13 +225,6 @@ void nsScrollbarButtonFrame::Notify() } } -void -nsScrollbarButtonFrame::MouseClicked(WidgetGUIEvent* aEvent) -{ - nsButtonBoxFrame::MouseClicked(aEvent); - //MouseClicked(); -} - nsresult nsScrollbarButtonFrame::GetChildWithTag(nsAtom* atom, nsIFrame* start, nsIFrame*& result) diff --git a/layout/xul/nsScrollbarButtonFrame.h b/layout/xul/nsScrollbarButtonFrame.h index a5bb753f433d..22d4582b4caf 100644 --- a/layout/xul/nsScrollbarButtonFrame.h +++ b/layout/xul/nsScrollbarButtonFrame.h @@ -63,8 +63,6 @@ public: nsEventStatus* aEventStatus) override; protected: - virtual void MouseClicked(mozilla::WidgetGUIEvent* aEvent) override; - void StartRepeat() { nsRepeatService::GetInstance()->Start(Notify, this, mContent->OwnerDoc(), diff --git a/layout/xul/nsTitleBarFrame.cpp b/layout/xul/nsTitleBarFrame.cpp index c3346cfa01cb..4d9c019208d0 100644 --- a/layout/xul/nsTitleBarFrame.cpp +++ b/layout/xul/nsTitleBarFrame.cpp @@ -168,23 +168,9 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, void nsTitleBarFrame::MouseClicked(WidgetMouseEvent* aEvent) { - bool isTrusted = false; - bool isShift = false; - bool isControl = false; - bool isAlt = false; - bool isMeta = false; - uint16_t inputSource = dom::MouseEventBinding::MOZ_SOURCE_UNKNOWN; - - if(aEvent) { - isShift = aEvent->IsShift(); - isControl = aEvent->IsControl(); - isAlt = aEvent->IsAlt(); - isMeta = aEvent->IsMeta(); - inputSource = aEvent->inputSource; - } - // Execute the oncommand event handler. - nsContentUtils::DispatchXULCommand(mContent, isTrusted, nullptr, - nullptr, isControl, isAlt, - isShift, isMeta, inputSource); + nsContentUtils::DispatchXULCommand(mContent, false, nullptr, + nullptr, aEvent->IsControl(), + aEvent->IsAlt(), aEvent->IsShift(), + aEvent->IsMeta(), aEvent->inputSource); } diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml index 74ab3c1abfac..8dbca4e97731 100644 --- a/toolkit/content/widgets/scrollbox.xml +++ b/toolkit/content/widgets/scrollbox.xml @@ -606,16 +606,6 @@ - - - - - - - - - - Date: Thu, 24 May 2018 14:44:09 +0100 Subject: [PATCH 033/116] Bug 1463115 - Try to skip irrelevant (collapsed/trimmed) whitespace when collecting used font faces for devtools inspector. r=jwatt --- dom/base/nsRange.cpp | 11 ++++++---- dom/base/nsRange.h | 3 ++- dom/chrome-webidl/InspectorUtils.webidl | 3 ++- layout/base/nsLayoutUtils.cpp | 28 +++++++++++++++++-------- layout/base/nsLayoutUtils.h | 6 ++++-- layout/generic/nsTextFrame.h | 4 ++-- layout/inspector/InspectorUtils.cpp | 4 +++- layout/inspector/InspectorUtils.h | 1 + 8 files changed, 40 insertions(+), 20 deletions(-) diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index 5a4f46da60f0..cde28563c486 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3157,7 +3157,7 @@ nsRange::GetClientRectsAndTexts( nsresult nsRange::GetUsedFontFaces(nsTArray>& aResult, - uint32_t aMaxRanges) + uint32_t aMaxRanges, bool aSkipCollapsedWhitespace) { NS_ENSURE_TRUE(mStart.Container(), NS_ERROR_UNEXPECTED); @@ -3201,17 +3201,20 @@ nsRange::GetUsedFontFaces(nsTArray>& aResult, int32_t offset = startContainer == endContainer ? mEnd.Offset() : content->GetText()->GetLength(); nsLayoutUtils::GetFontFacesForText(frame, mStart.Offset(), offset, - true, fontFaces, aMaxRanges); + true, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); continue; } if (node == endContainer) { nsLayoutUtils::GetFontFacesForText(frame, 0, mEnd.Offset(), - true, fontFaces, aMaxRanges); + true, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); continue; } } - nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges); + nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } // Take ownership of the InspectorFontFaces in the table and move them into diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h index 5e2bae621be2..f0ee5496e91d 100644 --- a/dom/base/nsRange.h +++ b/dom/base/nsRange.h @@ -270,7 +270,8 @@ public: // where each face was used). nsresult GetUsedFontFaces( nsTArray>& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); // nsIMutationObserver methods NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index 9f183d504856..1591f92a801b 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -65,7 +65,8 @@ namespace InspectorUtils { // to access via its .ranges attribute. [NewObject, Throws] sequence getUsedFontFaces( Range range, - optional unsigned long maxRanges = 0); + optional unsigned long maxRanges = 0, + optional boolean skipCollapsedWhitespace = true); sequence getCSSPseudoElementNames(); void addPseudoClassLock(Element element, diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index f07813a589ca..9e10105deaf6 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7851,14 +7851,16 @@ nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot) static void GetFontFacesForFramesInner(nsIFrame* aFrame, nsLayoutUtils::UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); if (aFrame->IsTextFrame()) { if (!aFrame->GetPrevContinuation()) { nsLayoutUtils::GetFontFacesForText(aFrame, 0, INT32_MAX, true, - aFontFaces, aMaxRanges); + aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } return; } @@ -7870,7 +7872,8 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); child = nsPlaceholderFrame::GetRealFrameFor(child); - GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges); + GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } } } @@ -7878,12 +7881,14 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, /* static */ nsresult nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); while (aFrame) { - GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges); + GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); aFrame = GetNextContinuationOrIBSplitSibling(aFrame); } @@ -7954,7 +7959,8 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); @@ -7994,9 +8000,13 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, } } - gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), - iter.ConvertOriginalToSkipped(fend)); - AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); + if (!aSkipCollapsedWhitespace || + (curr->HasAnyNoncollapsedCharacters() && + curr->HasNonSuppressedText())) { + gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), + iter.ConvertOriginalToSkipped(fend)); + AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); + } curr = next; } while (aFollowContinuations && curr); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 2675847487e8..3a4ad0c9dff9 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2288,7 +2288,8 @@ public: */ static nsresult GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); /** * Adds all font faces used within the specified range of text in aFrame, @@ -2302,7 +2303,8 @@ public: int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); /** * Walks the frame tree starting at aFrame looking for textRuns. diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 92754a7a92ad..af0a9ab14a81 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -666,6 +666,8 @@ public: uint32_t CountGraphemeClusters() const; + bool HasAnyNoncollapsedCharacters() override; + protected: virtual ~nsTextFrame(); @@ -882,8 +884,6 @@ protected: void ClearFrameOffsetCache(); - bool HasAnyNoncollapsedCharacters() override; - void ClearMetrics(ReflowOutput& aMetrics); /** diff --git a/layout/inspector/InspectorUtils.cpp b/layout/inspector/InspectorUtils.cpp index 9cef97b5a361..cc09fe684b85 100644 --- a/layout/inspector/InspectorUtils.cpp +++ b/layout/inspector/InspectorUtils.cpp @@ -617,10 +617,12 @@ InspectorUtils::GetCleanComputedStyleForElement(dom::Element* aElement, InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject, nsRange& aRange, uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv) { - nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges); + nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges, + aSkipCollapsedWhitespace); if (NS_FAILED(rv)) { aRv.Throw(rv); } diff --git a/layout/inspector/InspectorUtils.h b/layout/inspector/InspectorUtils.h index 8efa267b8f42..0c3f8ec09d55 100644 --- a/layout/inspector/InspectorUtils.h +++ b/layout/inspector/InspectorUtils.h @@ -225,6 +225,7 @@ public: nsRange& aRange, uint32_t aMaxRanges, // max number of ranges to // record for each face + bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv); From 0cc7412d4f7d327bbb8a3b65531415041dcb5fa8 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 25 May 2018 14:07:57 +0100 Subject: [PATCH 034/116] Bug 1464400 - Keep track of CSS generics when resolving to actual font families and faces, and expose as a new CSSGeneric attribute on InspectorFontFace. r=jwatt --- dom/chrome-webidl/InspectorUtils.webidl | 2 + gfx/thebes/gfxDWriteFontList.cpp | 4 +- gfx/thebes/gfxDWriteFontList.h | 2 +- gfx/thebes/gfxFcPlatformFontList.cpp | 17 ++--- gfx/thebes/gfxFcPlatformFontList.h | 6 +- gfx/thebes/gfxFont.h | 13 ++-- gfx/thebes/gfxFontEntry.h | 25 ++++++++ gfx/thebes/gfxFontFamilyList.h | 2 +- gfx/thebes/gfxGDIFontList.cpp | 4 +- gfx/thebes/gfxGDIFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.mm | 2 +- gfx/thebes/gfxPlatformFontList.cpp | 19 +++--- gfx/thebes/gfxPlatformFontList.h | 13 ++-- gfx/thebes/gfxTextRun.cpp | 57 +++++++++++------ gfx/thebes/gfxTextRun.h | 28 ++++++--- layout/inspector/InspectorFontFace.cpp | 14 +++++ layout/inspector/InspectorFontFace.h | 1 + layout/inspector/tests/chrome/chrome.ini | 1 + .../tests/chrome/test_fontFaceGeneric.xul | 62 +++++++++++++++++++ layout/style/ServoBindings.h | 2 +- 21 files changed, 214 insertions(+), 64 deletions(-) create mode 100644 layout/inspector/tests/chrome/test_fontFaceGeneric.xul diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index 1591f92a801b..0ab6a0ba6ea3 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -135,6 +135,8 @@ interface InspectorFontFace { readonly attribute DOMString CSSFamilyName; // a family name that could be used in CSS font-family // (not necessarily the actual name that was used, // due to aliases, generics, localized names, etc) + readonly attribute DOMString CSSGeneric; // CSS generic (serif, sans-serif, etc) that was mapped + // to this font, if any (frequently empty!) [NewObject,Throws] sequence getVariationAxes(); [NewObject,Throws] sequence getVariationInstances(); diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 06133658c765..e29f030f5be8 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1426,7 +1426,7 @@ gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName, bool gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1436,7 +1436,7 @@ gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(ff); + aOutput->AppendElement(FamilyAndGeneric(ff)); return true; } diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 37b62db94ca7..426c72cb5b1c 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -427,7 +427,7 @@ public: bool UseGDIFontTableAccess() { return mGDIFontTableAccess; } bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 987b08d19c88..5c0cd8f092b1 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -1893,7 +1893,7 @@ gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName, bool gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1941,7 +1941,7 @@ gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, // Because the FcConfigSubstitute call is quite expensive, we cache the // actual font families found via this process. So check the cache first: NS_ConvertUTF16toUTF8 familyToFind(familyName); - AutoTArray cachedFamilies; + AutoTArray cachedFamilies; if (mFcSubstituteCache.Get(familyToFind, &cachedFamilies)) { if (cachedFamilies.IsEmpty()) { return false; @@ -2090,7 +2090,7 @@ gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, void gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { bool usePrefFontList = false; @@ -2147,7 +2147,10 @@ gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, PrefFontList* prefFonts = FindGenericFamilies(genericToLookup, aLanguage); NS_ASSERTION(prefFonts, "null generic font list"); - aFamilyList.AppendElements(*prefFonts); + aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); + for (auto& f : *prefFonts) { + aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); + } } void @@ -2258,14 +2261,14 @@ gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric, FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric); if (mappedGeneric) { NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric)); - AutoTArray genericFamilies; + AutoTArray genericFamilies; if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName, &genericFamilies, FindFamiliesFlags(0))) { MOZ_ASSERT(genericFamilies.Length() == 1, "expected a single family"); - if (!prefFonts->Contains(genericFamilies[0])) { - prefFonts->AppendElement(genericFamilies[0]); + if (!prefFonts->Contains(genericFamilies[0].mFamily)) { + prefFonts->AppendElement(genericFamilies[0].mFamily); bool foundLang = !fcLang.IsEmpty() && PatternHasLang(font, ToFcChar8Ptr(fcLang.get())); diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 251990035dcd..63950d5e5ef1 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -305,7 +305,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; @@ -318,7 +318,7 @@ public: // override to use fontconfig lookup for generics void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) override; + nsTArray& aFamilyList) override; void ClearLangGroupPrefFonts() override; @@ -399,7 +399,7 @@ protected: // these pointers will be invalidated. InitFontList() flushes the cache // in this case. nsDataHashtable> mFcSubstituteCache; + nsTArray> mFcSubstituteCache; nsCOMPtr mCheckFontUpdatesTimer; nsCountedRef mLastConfig; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index e122e90d23c2..8eb7d160c91e 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -631,12 +631,17 @@ protected: }; struct gfxTextRange { - enum class MatchType : uint8_t { + enum class MatchType : uint16_t { + // The CSS generic that mapped to this font, if any. This field of + // the MatchType stores a FontFamilyType value as defined in the enum + // in gfxFontFamilyList.h. + kGenericMask = 0x00ff, + // Flags for recording the kind of font-matching that was used. // Note that multiple flags may be set on a single range. - kFontGroup = 0x01, - kPrefsFallback = 0x02, - kSystemFallback = 0x04 + kFontGroup = 0x0100, + kPrefsFallback = 0x0200, + kSystemFallback = 0x0400 }; gfxTextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont, MatchType aMatchType, diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index c1246ed90240..8e975a2bc7cf 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -925,4 +925,29 @@ protected: }; }; +// Struct used in the gfxFontGroup font list to keep track of a font family +// together with the CSS generic (if any) that was mapped to it in this +// particular case (so it can be reported to the DevTools font inspector). +struct FamilyAndGeneric final { + FamilyAndGeneric() + : mFamily(nullptr) + , mGeneric(mozilla::FontFamilyType::eFamily_none) + { + } + FamilyAndGeneric(const FamilyAndGeneric& aOther) + : mFamily(aOther.mFamily) + , mGeneric(aOther.mGeneric) + { + } + explicit FamilyAndGeneric(gfxFontFamily* aFamily, + mozilla::FontFamilyType aGeneric = + mozilla::FontFamilyType::eFamily_none) + : mFamily(aFamily) + , mGeneric(aGeneric) + { + } + gfxFontFamily* mFamily; + mozilla::FontFamilyType mGeneric; +}; + #endif diff --git a/gfx/thebes/gfxFontFamilyList.h b/gfx/thebes/gfxFontFamilyList.h index ccfd3476edf9..e60e789f7903 100644 --- a/gfx/thebes/gfxFontFamilyList.h +++ b/gfx/thebes/gfxFontFamilyList.h @@ -23,7 +23,7 @@ namespace mozilla { * between unquoted and quoted names for serializaiton */ -enum FontFamilyType : uint32_t { +enum FontFamilyType : uint8_t { eFamily_none = 0, // used when finding generics // explicitly named font family (e.g. Helvetica) diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index aff93de8aac0..1b83d7f74dfb 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -882,7 +882,7 @@ gfxGDIFontList::MakePlatformFont(const nsAString& aFontName, bool gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -892,7 +892,7 @@ gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(ff); + aOutput->AppendElement(FamilyAndGeneric(ff)); return true; } diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 8d18a0c9d125..8530497dd19c 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -326,7 +326,7 @@ public: gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index ee220b8a80ab..281341bfdc5a 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -156,7 +156,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index f42239e4b854..f7435257f377 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -1628,7 +1628,7 @@ static const char kSystemFont_system[] = "-apple-system"; bool gfxMacPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index faa30e86c11b..aebf33faeef8 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -751,7 +751,7 @@ gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily) bool gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -818,7 +818,7 @@ gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, } if (familyEntry) { - aOutput->AppendElement(familyEntry); + aOutput->AppendElement(FamilyAndGeneric(familyEntry)); return true; } @@ -1011,12 +1011,12 @@ gfxPlatformFontList::GetFontFamiliesFromGenericFamilies( gfxFontStyle style; style.language = aLangGroup; style.systemFont = false; - AutoTArray families; + AutoTArray families; FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0), &style); - for (gfxFontFamily* f : families) { - if (!aGenericFamilies->Contains(f)) { - aGenericFamilies->AppendElement(f); + for (const FamilyAndGeneric& f : families) { + if (!aGenericFamilies->Contains(f.mFamily)) { + aGenericFamilies->AppendElement(f.mFamily); } } } @@ -1055,7 +1055,7 @@ gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, void gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // map lang ==> langGroup nsAtom* langGroup = GetLangGroup(aLanguage); @@ -1068,7 +1068,10 @@ gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, GetPrefFontsLangGroup(aGenericType, prefLang); if (!prefFonts->IsEmpty()) { - aFamilyList.AppendElements(*prefFonts); + aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); + for (auto& f : *prefFonts) { + aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); + } } } diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 34f427a75817..3b89bd94d84d 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -166,7 +166,7 @@ public: // Return true if any match was found and appended, false if none. virtual bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); @@ -263,7 +263,7 @@ public: virtual void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList); + nsTArray& aFamilyList); nsTArray>* GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, @@ -305,6 +305,8 @@ public: bool AddWithLegacyFamilyName(const nsAString& aLegacyName, gfxFontEntry* aFontEntry); + static const char* GetGenericName(mozilla::FontFamilyType aGenericType); + protected: class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable { @@ -403,12 +405,13 @@ protected: gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { - AutoTArray families; + AutoTArray families; return FindAndAddFamilies(aFamily, &families, aFlags, aStyle, - aDevToCssSize) ? families[0] : nullptr; + aDevToCssSize) + ? families[0].mFamily : nullptr; } // Lookup family name in global family list without substitutions or @@ -488,8 +491,6 @@ protected: // helper function to map lang to lang group nsAtom* GetLangGroup(nsAtom* aLanguage); - static const char* GetGenericName(mozilla::FontFamilyType aGenericType); - // gfxFontInfoLoader overrides, used to load in font cmaps virtual void InitLoader() override; virtual bool LoadFontInfo() override; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 67982992e82f..f00f9ace5afa 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1796,7 +1796,7 @@ void gfxFontGroup::BuildFontList() { // initialize fonts in the font family list - AutoTArray fonts; + AutoTArray fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); // lookup fonts in the fontlist @@ -1822,14 +1822,14 @@ gfxFontGroup::BuildFontList() } // build the fontlist from the specified families - for (gfxFontFamily* fontFamily : fonts) { - AddFamilyToFontList(fontFamily); + for (const auto& f : fonts) { + AddFamilyToFontList(f.mFamily, f.mGeneric); } } void gfxFontGroup::AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // First, look up in the user font set... // If the fontSet matches the family, we must not look for a platform @@ -1853,7 +1853,8 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, } void -gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) +gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, + FontFamilyType aGeneric) { NS_ASSERTION(aFamily, "trying to add a null font family to fontlist"); AutoTArray fontEntryList; @@ -1861,7 +1862,7 @@ gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) // add these to the fontlist for (gfxFontEntry* fe : fontEntryList) { if (!HasFont(fe)) { - FamilyFace ff(aFamily, fe); + FamilyFace ff(aFamily, fe, aGeneric); if (fe->mIsUserFontContainer) { ff.CheckState(mSkipDrawing); } @@ -2064,7 +2065,7 @@ gfxFontGroup::GetDefaultFont() } gfxFont* -gfxFontGroup::GetFirstValidFont(uint32_t aCh) +gfxFontGroup::GetFirstValidFont(uint32_t aCh, FontFamilyType* aGeneric) { uint32_t count = mFonts.Length(); for (uint32_t i = 0; i < count; ++i) { @@ -2076,6 +2077,9 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh) // already have a font? gfxFont* font = ff.Font(); if (font) { + if (aGeneric) { + *aGeneric = ff.Generic(); + } return font; } @@ -2099,9 +2103,15 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh) font = GetFontAt(i, aCh); if (font) { + if (aGeneric) { + *aGeneric = mFonts[i].Generic(); + } return font; } } + if (aGeneric) { + *aGeneric = eFamily_none; + } return GetDefaultFont(); } @@ -2889,7 +2899,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* firstFont = GetFontAt(0, aCh); if (firstFont) { if (firstFont->HasCharacter(aCh)) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); return firstFont; } @@ -2904,7 +2915,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, font = FindFallbackFaceForChar(mFonts[0].Family(), aCh); } if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); return font; } } @@ -2954,6 +2966,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* font = ff.Font(); if (font) { if (font->HasCharacter(aCh)) { + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } continue; @@ -2982,7 +2996,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (pfe && pfe->HasCharacter(aCh)) { font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[i].Generic()); return font; } } @@ -2991,7 +3006,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, // build the font via GetFontAt font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[i].Generic()); return font; } } @@ -3004,7 +3020,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, "should only do fallback once per font family"); font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } } else { @@ -3015,7 +3032,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (!fe->mIsUserFontContainer && !fe->IsUserFont()) { font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } } @@ -3084,11 +3102,13 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, // initialize prevFont to the group's primary font, so that this will be // used for string-initial control chars, etc rather than risk hitting font // fallback for these (bug 716229) - gfxFont *prevFont = GetFirstValidFont(); + FontFamilyType generic = eFamily_none; + gfxFont *prevFont = GetFirstValidFont(' ', &generic); // if we use the initial value of prevFont, we treat this as a match from // the font group; fixes bug 978313 - gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup; + gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(generic); for (uint32_t i = 0; i < aLength; i++) { @@ -3138,7 +3158,8 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, && !gfxFontUtils::IsJoinControl(ch) && !gfxFontUtils::IsJoinCauser(prevCh) && !gfxFontUtils::IsVarSelector(ch)))) { - matchType = gfxTextRange::MatchType::kFontGroup; + matchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); } else { font = FindFontForChar(ch, prevCh, nextCh, aRunScript, prevFont, &matchType); @@ -3146,9 +3167,9 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, #ifndef RELEASE_OR_BETA if (MOZ_UNLIKELY(mTextPerf)) { - if (matchType == gfxTextRange::MatchType::kPrefsFallback) { + if (matchType & gfxTextRange::MatchType::kPrefsFallback) { mTextPerf->current.fallbackPrefs++; - } else if (matchType == gfxTextRange::MatchType::kSystemFallback) { + } else if (matchType & gfxTextRange::MatchType::kSystemFallback) { mTextPerf->current.fallbackSystem++; } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index b55d25676373..ed2e1a0c93fb 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -864,8 +864,11 @@ public: virtual ~gfxFontGroup(); // Returns first valid font in the fontlist or default font. - // Initiates userfont loads if userfont not loaded - gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); + // Initiates userfont loads if userfont not loaded. + // aGeneric: if non-null, returns the CSS generic type that was mapped to + // this font + gfxFont* GetFirstValidFont(uint32_t aCh = 0x20, + mozilla::FontFamilyType* aGeneric = nullptr); // Returns the first font in the font-group that has an OpenType MATH table, // or null if no such font is available. The GetMathConstant methods may be @@ -1025,13 +1028,15 @@ protected: class FamilyFace { public: FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), + mGeneric(mozilla::eFamily_none), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { } - FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) - : mFamily(aFamily), mFontCreated(true), + FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont, + mozilla::FontFamilyType aGeneric) + : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(true), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFont, "font pointer must not be null"); @@ -1042,8 +1047,9 @@ protected: NS_ADDREF(aFont); } - FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry) - : mFamily(aFamily), mFontCreated(false), + FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, + mozilla::FontFamilyType aGeneric) + : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); @@ -1056,6 +1062,7 @@ protected: FamilyFace(const FamilyFace& aOtherFamilyFace) : mFamily(aOtherFamilyFace.mFamily), + mGeneric(aOtherFamilyFace.mGeneric), mFontCreated(aOtherFamilyFace.mFontCreated), mLoading(aOtherFamilyFace.mLoading), mInvalid(aOtherFamilyFace.mInvalid), @@ -1088,6 +1095,7 @@ protected: } mFamily = aOther.mFamily; + mGeneric = aOther.mGeneric; mFontCreated = aOther.mFontCreated; mLoading = aOther.mLoading; mInvalid = aOther.mInvalid; @@ -1112,6 +1120,8 @@ protected: return mFontCreated ? mFont->GetFontEntry() : mFontEntry; } + mozilla::FontFamilyType Generic() const { return mGeneric; } + bool IsUserFontContainer() const { return FontEntry()->mIsUserFontContainer; } @@ -1148,6 +1158,7 @@ protected: gfxFont* MOZ_OWNING_REF mFont; gfxFontEntry* MOZ_OWNING_REF mFontEntry; }; + mozilla::FontFamilyType mGeneric; bool mFontCreated : 1; bool mLoading : 1; bool mInvalid : 1; @@ -1259,10 +1270,11 @@ protected: // lookup and add a font with a given name (i.e. *not* a generic!) void AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList); + nsTArray& aFamilyList); // do style selection and add entries to list - void AddFamilyToFontList(gfxFontFamily* aFamily); + void AddFamilyToFontList(gfxFontFamily* aFamily, + mozilla::FontFamilyType aGeneric); }; // A "missing font recorder" is to be used during text-run creation to keep diff --git a/layout/inspector/InspectorFontFace.cpp b/layout/inspector/InspectorFontFace.cpp index ea099428f8e9..1d28177ebb70 100644 --- a/layout/inspector/InspectorFontFace.cpp +++ b/layout/inspector/InspectorFontFace.cpp @@ -6,6 +6,7 @@ #include "InspectorFontFace.h" +#include "gfxPlatformFontList.h" #include "gfxTextRun.h" #include "gfxUserFontSet.h" #include "nsFontFaceLoader.h" @@ -55,6 +56,19 @@ InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) aCSSFamilyName = mFontEntry->FamilyName(); } +void +InspectorFontFace::GetCSSGeneric(nsAString& aName) +{ + auto genericType = + FontFamilyType(mMatchType & gfxTextRange::MatchType::kGenericMask); + if (genericType >= FontFamilyType::eFamily_generic_first && + genericType <= FontFamilyType::eFamily_generic_last) { + aName.AssignASCII(gfxPlatformFontList::GetGenericName(genericType)); + } else { + aName.Truncate(0); + } +} + ServoFontFaceRule* InspectorFontFace::GetRule() { diff --git a/layout/inspector/InspectorFontFace.h b/layout/inspector/InspectorFontFace.h index 501cf6bb86f2..a123bbcbb9de 100644 --- a/layout/inspector/InspectorFontFace.h +++ b/layout/inspector/InspectorFontFace.h @@ -56,6 +56,7 @@ public: bool FromSystemFallback(); void GetName(nsAString& aName); void GetCSSFamilyName(nsAString& aCSSFamilyName); + void GetCSSGeneric(nsAString& aGeneric); ServoFontFaceRule* GetRule(); int32_t SrcIndex(); void GetURI(nsAString& aURI); diff --git a/layout/inspector/tests/chrome/chrome.ini b/layout/inspector/tests/chrome/chrome.ini index 3d7fc5affcf7..a8866410d9ba 100644 --- a/layout/inspector/tests/chrome/chrome.ini +++ b/layout/inspector/tests/chrome/chrome.ini @@ -28,3 +28,4 @@ support-files = skip-if = (os == 'win' || os == 'linux' || os == 'mac') # bug 1433438, bug 1456855, bug 1456856 support-files = test_fontVariationsAPI.css +[test_fontFaceGeneric.xul] diff --git a/layout/inspector/tests/chrome/test_fontFaceGeneric.xul b/layout/inspector/tests/chrome/test_fontFaceGeneric.xul new file mode 100644 index 000000000000..6c97f7f28c76 --- /dev/null +++ b/layout/inspector/tests/chrome/test_fontFaceGeneric.xul @@ -0,0 +1,62 @@ + + + + + + + + +
test one
+
test two
+
test three
+ + +
diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index 193f2c1d5961..6179fbe40424 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -36,7 +36,7 @@ struct nsFont; namespace mozilla { class FontFamilyList; struct FontFamilyName; - enum FontFamilyType : uint32_t; + enum FontFamilyType : uint8_t; class SharedFontList; enum class CSSPseudoElementType : uint8_t; struct Keyframe; From ee72038b8e0ede6ae5713ef27a59131e2b2184d4 Mon Sep 17 00:00:00 2001 From: ffxbld Date: Fri, 1 Jun 2018 15:56:55 +0100 Subject: [PATCH 035/116] No bug, Automated HSTS preload list update from task BqRcopwHQbGAhBJA_2Vuzw Summary: No bug, Automated HPKP preload list update from task BqRcopwHQbGAhBJA_2Vuzw No bug, Automated blocklist update from task BqRcopwHQbGAhBJA_2Vuzw No bug, Automated remote settings update from task BqRcopwHQbGAhBJA_2Vuzw Reviewers: mtabara, jlund Reviewed By: mtabara Differential Revision: https://phabricator.services.mozilla.com/D1473 --HG-- extra : rebase_source : 8326a0602e40d57f8fb3da5dd047a5b3840bc77f --- browser/app/blocklist.xml | 10 +++++++++- security/manager/ssl/StaticHPKPins.h | 5 +++-- security/manager/ssl/nsSTSPreloadList.inc | 20 ++++++++++++++++++- .../settings/dumps/blocklists/addons.json | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/browser/app/blocklist.xml b/browser/app/blocklist.xml index f081caa44086..4be2eacb6c89 100644 --- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -1,5 +1,5 @@ - + @@ -2259,6 +2259,14 @@ + + + + + + + + diff --git a/security/manager/ssl/StaticHPKPins.h b/security/manager/ssl/StaticHPKPins.h index 65a64ea55c75..e75a7f76a445 100644 --- a/security/manager/ssl/StaticHPKPins.h +++ b/security/manager/ssl/StaticHPKPins.h @@ -719,6 +719,7 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = { { "chromiumbugs.appspot.com", true, false, false, -1, &kPinset_google_root_pems }, { "chromiumcodereview.appspot.com", true, false, false, -1, &kPinset_google_root_pems }, { "cl.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, + { "classroom.google.com", true, false, false, -1, &kPinset_google_root_pems }, { "cloud.google.com", true, false, false, -1, &kPinset_google_root_pems }, { "cn.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, { "co.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, @@ -1159,8 +1160,8 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = { { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo }, }; -// Pinning Preload List Length = 485; +// Pinning Preload List Length = 486; static const int32_t kUnknownId = -1; -static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1534413959302000); +static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1536228297509000); diff --git a/security/manager/ssl/nsSTSPreloadList.inc b/security/manager/ssl/nsSTSPreloadList.inc index c660d98f868d..54088c53f80f 100644 --- a/security/manager/ssl/nsSTSPreloadList.inc +++ b/security/manager/ssl/nsSTSPreloadList.inc @@ -8,7 +8,7 @@ /*****************************************************************************/ #include -const PRTime gPreloadListExpirationTime = INT64_C(1536833056230000); +const PRTime gPreloadListExpirationTime = INT64_C(1538647409468000); %% 0-1.party, 1 0.me.uk, 1 @@ -4162,6 +4162,7 @@ beautykat.ru, 1 bebef.de, 1 bebefofuxo.com.br, 1 bebes.uno, 1 +bebest.gov, 1 bebetrotteur.com, 1 bebout.domains, 1 beccajoshwedding.com, 1 @@ -4357,6 +4358,7 @@ bentrask.com, 1 benzi.io, 1 benzou-space.com, 1 beoordelingen.be, 1 +bep.gov, 1 bephoenix.org.uk, 1 bequiia.com, 1 beranovi.com, 1 @@ -4551,6 +4553,7 @@ bezemkast.nl, 1 bezoomnyville.com, 1 bezpecnostsiti.cf, 1 bfam.tv, 1 +bfem.gov, 1 bfgcdn.com, 1 bfi.wien, 0 bflix.tv, 1 @@ -6548,6 +6551,7 @@ cbcf.info, 1 cbd.supply, 1 cbdev.de, 1 cbecrft.net, 1 +cbi-epa.gov, 1 cbintermountainrealty.com, 1 cbmusa.com, 1 cbr-xml-daily.ru, 1 @@ -7318,6 +7322,7 @@ classdojo.com, 1 classicalpilates.ca, 1 classics.io, 1 classpoint.cz, 1 +classroom.google.com, 1 classroomcountdown.co.nz, 1 classteaching.com.au, 1 claster.it, 1 @@ -10665,6 +10670,7 @@ e-baraxolka.ru, 1 e-bikesdirect.co.uk, 1 e-biografias.net, 1 e-cottage.com.br, 1 +e-enterprise.gov, 1 e-hon.link, 1 e-id.ee, 1 e-kontakti.fi, 1 @@ -11416,6 +11422,7 @@ energyaupair.se, 1 energydrinkblog.de, 1 energyelephant.com, 1 energyled.com.br, 1 +energystar.gov, 1 enersaveapp.org, 1 enersec.co.uk, 1 enet-navigator.de, 1 @@ -12275,6 +12282,7 @@ eydesignguidelines.com, 1 eyecandy.gr, 1 eyeglasses.com, 0 eyelashconcept.com, 1 +eyenote.gov, 1 eyeonid.com, 1 eyep.me, 1 eyes-berg.ch, 1 @@ -12587,6 +12595,7 @@ fdicig.gov, 1 fdicoig.gov, 1 fdlibre.eu, 1 fdm.ro, 1 +fdms.gov, 1 fdn.one, 1 fdsys.gov, 0 feac.us, 1 @@ -12601,6 +12610,7 @@ feb.gov, 1 fecik.sk, 1 fed51.com, 1 fedbizopps.gov, 1 +fedcenter.gov, 1 federalinvestments.gov, 1 federaljobs.gov, 1 federalreserve.gov, 1 @@ -14505,6 +14515,7 @@ glidingshop.cz, 1 glidingshop.de, 1 glidingshop.eu, 1 glloq.org, 1 +glnpo.gov, 1 glob-coin.com, 1 global-adult-webcams.com, 1 global-lights.ma, 1 @@ -14657,6 +14668,7 @@ goldstein.tel, 1 goldwater.gov, 1 goldwaterfoundation.gov, 1 goldwaterscholarship.gov, 1 +golearn.gov, 1 golf18network.com, 1 golfburn.com, 1 golfhausmallorca.com, 1 @@ -14889,6 +14901,7 @@ greenenergysolution.uk, 1 greener.pl, 1 greenglam.biz, 1 greengoblindev.com, 1 +greengov.gov, 1 greenhats.de, 1 greenitpark.net, 1 greenliquidsystem.com, 1 @@ -23304,6 +23317,7 @@ mondial-movers.nl, 1 mondo-it.ch, 1 moneychangersoftware.com, 1 moneycredit.eu, 1 +moneyfactory.gov, 1 moneygo.se, 1 moneyhouse.de, 1 moneypark.ch, 1 @@ -24345,6 +24359,7 @@ nbayouxi.com, 1 nbgrooves.de, 1 nbhorsetraining.com, 1 nbib.gov, 1 +nbis.gov, 1 nbl.org.tw, 1 nbp.com.pk, 1 nbrain.de, 1 @@ -28964,6 +28979,7 @@ releasetimes.io, 1 reliancebank.bank, 1 reliant3sixty.com, 1 religiousforums.com, 1 +relocatefeds.gov, 1 relsak.cz, 1 relvan.com, 1 rem0te.net, 1 @@ -35033,6 +35049,7 @@ townofbridgewater.ca, 1 towsonroofers.com, 1 towywebdesigns.uk, 1 tox.im, 1 +tox21.gov, 1 toxicboot.com, 1 toxicip.com, 1 toymania.de, 1 @@ -35942,6 +35959,7 @@ urbanmelbourne.info, 1 urbanmic.com, 1 urbannewsservice.com, 1 urbansparrow.in, 1 +urbanwaters.gov, 1 urbanwildlifealliance.org, 0 urbexdk.nl, 1 urcentral.com, 1 diff --git a/services/settings/dumps/blocklists/addons.json b/services/settings/dumps/blocklists/addons.json index be57e0364938..72d5370e056f 100644 --- a/services/settings/dumps/blocklists/addons.json +++ b/services/settings/dumps/blocklists/addons.json @@ -1 +1 @@ -{"data":[{"guid":"/^(({41c14ab8-9958-44bf-b74e-af54c1f169a6})|({78054cb2-e3e8-4070-a8ad-3fd69c8e4707})|({0089b179-8f3d-44d9-bb18-582843b0757a})|({f44ddcb4-4cc0-4866-92fa-eefda60c6720})|({1893d673-7953-4870-8069-baac49ce3335})|({fb28cac0-c2aa-4e0c-a614-cf3641196237})|({d7dee150-da14-45ba-afca-02c7a79ad805})|(RandomNameTest@RandomNameTest\\.com )|(corpsearchengine@mail\\.ru)|(support@work\\.org))$/","prefs":[],"schema":1525377099963,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1458330","why":"These are malicious add-ons that inject remote scripts and use deceptive names.","name":"\"Table\" add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3a123214-b4b6-410c-a061-bbaf0d168d31","last_modified":1525377135149},{"guid":"/((@extcorp\\.[a-z]+)|(@brcorporation\\.com)|(@brmodcorp\\.com)|(@teset\\.com)|(@modext\\.tech)|(@ext?mod\\.net)|(@browcorporation\\.org)|(@omegacorporation\\.org)|(@browmodule\\.com)|(@corpext\\.net)|({6b50ddac-f5e0-4d9e-945b-e4165bfea5d6})|({fab6484f-b8a7-4ba9-a041-0f948518b80c})|({b797035a-7f29-4ff5-bd19-77f1b5e464b1})|({0f612416-5c5a-4ec8-b482-eb546af9cac4}))$/","prefs":[],"schema":1525290095999,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1458330","why":"These are malicious add-ons that inject remote scripts and use deceptive names.","name":"\"Table\" add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3ab9f100-e253-4080-b3e5-652f842ddb7a","last_modified":1525377099954},{"guid":"/^({b99ae7b1-aabb-4674-ba8f-14ed32d04e76})|({dfa77d38-f67b-4c41-80d5-96470d804d09})$/","prefs":[],"schema":1524146566650,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1455291","why":"These add-ons claim to be the flash plugin.","name":"Flash Plugin (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"96b137e6-8cb5-44d6-9a34-4a4a76fb5e38","last_modified":1524147337556},{"guid":"/^({6ecb9f49-90f0-43a1-8f8a-e809ea4f732b})|(@googledashboard)|(@smashdashboard)|(@smash_tv)|(@smash_mov)|(@smashmovs)|(@smashtvs)|(@FirefoxUpdate)|({92b9e511-ac81-4d47-9b8f-f92dc872447e})|({3c841114-da8c-44ea-8303-78264edfe60b})|({116a0754-20eb-4fe5-bd35-575867a0b89e})|({6e6ff0fd-4ae4-49ae-ac0c-e2527e12359b})|({f992ac88-79d3-4960-870e-92c342ed3491})|({6ecb9f49-90f0-43a1-8f8a-e809ea4f732b})|({a512297e-4d3a-468c-bd1a-f77bd093f925})|({08c28c16-9fb6-4b32-9868-db37c1668f94})|({b4ab1a1d-e137-4c59-94d5-4f509358a81d})|({feedf4f8-08c1-451f-a717-f08233a64ec9})$/","prefs":[],"schema":1524139371832,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1454691","why":"This malware prevents itself from getting uninstalled ","name":"Malware"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"feb2d0d7-1b76-4dba-bf84-42873a92af5f","last_modified":1524141477640},{"guid":"{872f20ea-196e-4d11-8835-1cc4c877b1b8}","prefs":[],"schema":1523734896380,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1454413","why":"Extension claims to be Flash Player","name":"Flash Player (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"1e5f5cb2-346c-422a-9aaa-29d8760949d2","last_modified":1523897202689},{"guid":"/(__TEMPLATE__APPLICATION__@ruta-mapa\\.com)|(application-3@findizer\\.fr)|(application2@allo-pages\\.fr)|(application2@bilan-imc\\.fr)|(application2@lettres\\.net)|(application2@search-maps-finder\\.com)|(application-imcpeso@imc-peso\\.com)|(application-meuimc@meu-imc\\.com)|(application-us2@factorlove)|(application-us@misterdirections)|(application-us@yummmi\\.es)|(application@amiouze\\.fr)|(application@astrolignes\\.com)|(application@blotyn\\.com)|(application@bmi-result\\.com)|(application@bmi-tw\\.com)|(application@calcolo-bmi\\.com)|(application@cartes-itineraires\\.com)|(application@convertisseur\\.pro)|(application@de-findizer\\.fr)|(application@de-super-rezepte\\.com)|(application@dermabeauty\\.fr)|(application@dev\\.squel\\.v2)|(application@eu-my-drivingdirections\\.com)|(application@fr-allo-pages\\.fr)|(application@fr-catizz\\.com)|(application@fr-mr-traduction\\.com)|(application@good-recettes\\.com)|(application@horaires\\.voyage)|(application@imc-calcular\\.com)|(application@imc-peso\\.com)|(application@it-mio-percorso\\.com)|(application@iti-maps\\.fr)|(application@itineraire\\.info)|(application@lbc-search\\.com)|(application@les-pages\\.com)|(application@lovincalculator\\.com)|(application@lovintest\\.com)|(application@masowe\\.com)|(application@matchs\\.direct)|(application@mein-bmi\\.com)|(application@mes-resultats\\.com)|(application@mestaf\\.com)|(application@meu-imc\\.com)|(application@mon-calcul-imc\\.fr)|(application@mon-juste-poids\\.com)|(application@mon-trajet\\.com)|(application@my-drivingdirections\\.com)|(application@people-show\\.com)|(application@plans-reduc\\.fr)|(application@point-meteo\\.fr)|(application@poulixo\\.com)|(application@quipage\\.fr)|(application@quizdeamor\\.com)|(application@quizdoamor\\.com)|(application@quotient-retraite\\.fr)|(application@recettes\\.net)|(application@routenplaner-karten\\.com)|(application@ruta-mapa\\.com)|(application@satellite\\.dev\\.squel\\.v2)|(application@search-bilan-imc\\.fr)|(application@search-maps-finder\\.com)|(application@slimness\\.fr)|(application@start-bmi\\.com)|(application@tests-moi\\.com)|(application@tousmesjeux\\.fr)|(application@toutlannuaire\\.fr)|(application@tuto-diy\\.com)|(application@ubersetzung-app\\.com)|(application@uk-cookyummy\\.com)|(application@uk-howlogin\\.me)|(application@uk-myloap\\.com)|(application@voyagevoyage\\.co)|(application@wikimot\\.fr)|(application@www\\.plans-reduc\\.fr)|(application@yummmi\\.es)|(application@yummmies\\.be)|(application@yummmies\\.ch)|(application@yummmies\\.fr)|(application@yummmies\\.lu)|(application@zikplay\\.fr)|(applicationY@search-maps-finder\\.com)|(cmesapps@findizer\\.fr)|(findizer-shopping@jetpack)|(\\{8aaebb36-1488-4022-b7ec-29b790d12c17\\})/","prefs":[],"schema":1523216496621,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1452648","why":"Those add-ons do not provide a real functionality for users, other than silently tracking browsing behavior.","name":"Tracking Add-ons (harmful)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"36f97298-8bef-4372-a548-eb829413bee9","last_modified":1523286321447},{"guid":"adbeaver@adbeaver.org","prefs":[],"schema":1521630548030,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1445031","why":"This add-on generates numerous errors when loading Facebook, caused by ad injection included in it. Users who want to continue using this add-on can enable it in the Add-ons Manager.","name":"AdBeaver"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0"}],"id":"baf7f735-d6b6-410a-8cc8-25c60f7c57e2","last_modified":1522103097333},{"guid":"{44685ba6-68b3-4895-879e-4efa29dfb578}","prefs":[],"schema":1521565140013,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1447042","why":"This add-on impersonates a Flash tool and runs remote code on users' systems.","name":"FF Flash Manager"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"547037f2-97ae-435a-863c-efd7532668cd","last_modified":1521630548023},{"guid":"/^.*extension.*@asdf\\.pl$/","prefs":[],"schema":1520451695869,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1444037","why":"These add-ons are using deceptive names and taking over Facebook accounts to post spam content.","name":"Facebook spammers"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3d55fab0-ec1a-4bca-84c9-3b74f5d01509","last_modified":1520527480321},{"guid":"/^(addon@fasterweb\\.com|\\{5f398d3f-25db-47f5-b422-aa2364ff6c0b\\}|addon@fasterp\\.com|addon@calculator)$/","prefs":[],"schema":1520338910918,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1443478","why":"These are malicious add-ons that use deceptive names and run remote scripts.","name":"FasterWeb add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"f58729ec-f93c-41d9-870d-dd9c9fd811b6","last_modified":1520358450708},{"guid":"{42baa93e-0cff-4289-b79e-6ae88df668c4}","prefs":[],"schema":1520336325565,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1443196","why":"The add-on claims to be \"Adobe Shockwave Flash Player\"","name":"Adobe Shockwave Flash Player (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"0cd723fe-d33d-43a0-b84f-7a3cad253212","last_modified":1520338780397},{"guid":"/{0c9970a2-6874-483b-a486-2296cfe251c2}|{01c9a4a4-06dd-426b-9500-2ea6fe841b88}|{1c981c7c-30e0-4ed2-955d-6b370e0a9d19}|{2aa275f8-fabc-4766-95b2-ecfc73db310b}|{2cac0be1-10a2-4a0d-b8c5-787837ea5955}|{2eb66f6c-94b3-44f5-9de2-22371236ec99}|{2f8aade6-8717-4277-b8b1-55172d364903}|{3c27c34f-8775-491a-a1c9-fcb15beb26d3}|{3f4dea3e-dbfc-428f-a88b-36908c459e20}|{3f4191fa-8f16-47d2-9414-36bfc9e0c2bf}|{4c140bc5-c2ad-41c3-a407-749473530904}|{05a21129-af2a-464c-809f-f2df4addf209}|{5da81d3d-5db1-432a-affc-4a2fe9a70749}|{5f4e63e4-351f-4a21-a8e5-e50dc72b5566}|{7c1df23b-1fd8-42b9-8752-71fff2b979de}|{7d5e24a1-7bef-4d09-a952-b9519ec00d20}|{7d932012-b4dd-42cc-8a78-b15ca82d0e61}|{7f8bc48d-1c7c-41a0-8534-54adc079338f}|{8a61507d-dc2f-4507-a9b7-7e33b8cbc31b}|{09c8fa16-4eec-4f78-b19d-9b24b1b57e1e}|{9ce2a636-0e49-4b8e-ad17-d0c156c963b0}|{11df9391-dba5-4fe2-bd48-37a9182b796d}|{23c65153-c21e-430a-a2dc-0793410a870d}|{36a4269e-4eef-4538-baea-9dafbf6a8e2f}|{37f8e483-c782-40ed-82e9-36f101b9e41f}|{63df223d-51cf-4f76-aad8-bbc94c895ed2}|{72c1ca96-c05d-46a7-bce1-c507ec3db4ea}|{76ce213c-8e57-4a14-b60a-67a5519bd7a7}|{79db6c96-d65a-4a64-a892-3d26bd02d2d9}|{81ac42f3-3d17-4cff-85af-8b7f89c8826b}|{83d38ac3-121b-4f28-bf9c-1220bd3c643b}|{86d98522-5d42-41d5-83c2-fc57f260a3d9}|{0111c475-01e6-42ea-a9b4-27bed9eb6092}|{214cb48a-ce31-4e48-82cf-a55061f1b766}|{216e0bcc-8a23-4069-8b63-d9528b437258}|{226b0fe6-f80f-48f1-9d8d-0b7a1a04e537}|{302ef84b-2feb-460e-85ca-f5397a77aa6a}|{408a506b-2336-4671-a490-83a1094b4097}|{419be4e9-c981-478e-baa0-937cf1eea1e8}|{0432b92a-bfcf-41b9-b5f0-df9629feece1}|{449e185a-dd91-4f7b-a23a-bbf6c1ca9435}|{591d1b73-5eae-47f4-a41f-8081d58d49bf}|{869b5825-e344-4375-839b-085d3c09ab9f}|{919fed43-3961-48d9-b0ef-893054f4f6f1}|{01166e60-d740-440c-b640-6bf964504b3c}|{2134e327-8060-441c-ba68-b167b82ff5bc}|{02328ee7-a82b-4983-a5f7-d0fc353698f0}|{6072a2a8-f1bc-4c9c-b836-7ac53e3f51e4}|{28044ca8-8e90-435e-bc63-a757af2fb6be}|{28092fa3-9c52-4a41-996d-c43e249c5f08}|{31680d42-c80d-4f8a-86d3-cd4930620369}|{92111c8d-0850-4606-904a-783d273a2059}|{446122cd-cd92-4d0c-9426-4ee0d28f6dca}|{829827cd-03be-4fed-af96-dd5997806fb4}|{4479446e-40f3-48af-ab85-7e3bb4468227}|{9263519f-ca57-4178-b743-2553a40a4bf1}|{71639610-9cc3-47e0-86ed-d5b99eaa41d5}|{84406197-6d37-437c-8d82-ae624b857355}|{93017064-dfd4-425e-a700-353f332ede37}|{a0ab16af-3384-4dbe-8722-476ce3947873}|{a0c54bd8-7817-4a40-b657-6dc7d59bd961}|{a2de96bc-e77f-4805-92c0-95c9a2023c6a}|{a3fbc8be-dac2-4971-b76a-908464cfa0e0}|{a42e5d48-6175-49e3-9e40-0188cde9c5c6}|{a893296e-5f54-43f9-a849-f12dcdee2c98}|{ac296b47-7c03-486f-a1d6-c48b24419749}|{b26bf964-7aa6-44f4-a2a9-d55af4b4eec0}|{be981b5e-1d9d-40dc-bd4f-47a7a027611c}|{be37931c-af60-4337-8708-63889f36445d}|{bfd92dfd-b293-4828-90c1-66af2ac688e6}|{c5cf4d08-0a33-4aa3-a40d-d4911bcc1da7}|{c488a8f5-ea3d-408d-809e-44e82c06ad9d}|{c661c2dc-00f9-4dc1-a9f6-bb2b7e1a4f8d}|{cd28aa38-d2f1-45a3-96c3-6cfd4702ef51}|{cd89045b-2e06-46bb-9e34-48e8799e5ef2}|{cf9d96ff-5997-439a-b32b-98214c621eee}|{d14acee6-f32b-4aa3-a802-6616003fc6a8}|{d97223b8-44e5-46c7-8ab5-e1d8986daf44}|{ddae89bd-6793-45d8-8ec9-7f4fb7212378}|{de3b1909-d4da-45e9-8da5-7d36a30e2fc6}|{df09f268-3c92-49db-8c31-6a25a6643896}|{e5bc3951-c837-4c98-9643-3c113fc8cf5e}|{e9ccb1f2-a8ba-4346-b43b-0d5582bce414}|{e341ed12-a703-47fe-b8dd-5948c38070e4}|{e2139287-2b0d-4f54-b3b1-c9a06c597223}|{ed352072-ddf0-4cb4-9cb6-d8aa3741c2de}|{f0b809eb-be22-432f-b26f-b1cadd1755b9}|{f1bce8e4-9936-495b-bf48-52850c7250ab}|{f01c3add-dc6d-4f35-a498-6b4279aa2ffa}|{f9e1ad25-5961-4cc5-8d66-5496c438a125}|{f4262989-6de0-4604-918f-663b85fad605}|{fc0d55bd-3c50-4139-9409-7df7c1114a9d}/","prefs":[],"schema":1519766961483,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1439702","why":"This malicious add-on claims to be a Firefox \"helper\" or \"updater\" or similar.","name":"FF updater (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"48b14881-5f6b-4e48-afc5-3d9a7fae26a3","last_modified":1519826648080},{"guid":"{44e4b2cf-77ba-4f76-aca7-f3fcbc2dda2f} ","prefs":[],"schema":1519414957616,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1440821","why":"This is a malicious add-on that uses a deceptive name and runs remote code.","name":"AntiVirus for Firefox"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2447476f-043b-4d0b-9d3c-8e859c97d950","last_modified":1519429178266},{"guid":"{f3c31b34-862c-4bc8-a98f-910cc6314a86}","prefs":[],"schema":1519242096699,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1440736","why":"This is a malicious add-on that is masked as an official Adobe Updater and runs malicious code.","name":"Adobe Updater (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"adfd98ef-cebc-406b-b1e0-61bd4c71e4b1","last_modified":1519409417397},{"guid":"/^(\\{fd0c36fa-6a29-4246-810b-0bb4800019cb\\}|\\{b9c1e5bf-6585-4766-93fc-26313ac59999\\}|\\{3de25fff-25e8-40e9-9ad9-fdb3b38bb2f4\\})$/","prefs":[],"schema":1519069296530,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1439432","why":"These are malicious add-ons that are masked as an official Adobe Updater and run malicious code.","name":"Adobe Updater"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"4e28ba5c-af62-4e53-a7a1-d33334571cf8","last_modified":1519078890592},{"guid":"/^(\\{01c9a4a4-06dd-426b-9500-2ea6fe841b88\\}|{5e024309-042c-4b9d-a634-5d92cf9c7514\\}|{f4262989-6de0-4604-918f-663b85fad605\\}|{e341ed12-a703-47fe-b8dd-5948c38070e4\\}|{cd89045b-2e06-46bb-9e34-48e8799e5ef2\\}|{ac296b47-7c03-486f-a1d6-c48b24419749\\}|{5da81d3d-5db1-432a-affc-4a2fe9a70749\\}|{df09f268-3c92-49db-8c31-6a25a6643896\\}|{81ac42f3-3d17-4cff-85af-8b7f89c8826b\\}|{09c8fa16-4eec-4f78-b19d-9b24b1b57e1e\\}|{71639610-9cc3-47e0-86ed-d5b99eaa41d5\\}|{83d38ac3-121b-4f28-bf9c-1220bd3c643b\\}|{7f8bc48d-1c7c-41a0-8534-54adc079338f\\})$/","prefs":[],"schema":1518550894975,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1438028","why":"These are malicious add-ons that inject remote scripts into popular websites.","name":"Page Marker add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"cc5848e8-23d5-4655-b45c-dc239839b74e","last_modified":1518640450735},{"guid":"/^(https|youtube)@vietbacsecurity\\.com$/","prefs":[],"schema":1517909997354,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1435974","why":"These add-ons contain malicious functionality, violating the users privacy and security.","name":"HTTPS and Youtube downloader (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"646e2384-f894-41bf-b7fc-8879e0095109","last_modified":1517910100624},{"guid":"{ed352072-ddf0-4cb4-9cb6-d8aa3741c2de}","prefs":[],"schema":1517514097126,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1434893","why":"This is a malicious add-on that injects remote scripts into popular pages while pretending to do something else.","name":"Image previewer"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2104a522-bb2f-4b04-ad0d-b0c571644552","last_modified":1517577111194},{"guid":"/^(\\{0b24cf69-02b8-407d-83db-e7af04fc1f3e\\})|(\\{6feed48d-41d4-49b8-b7d6-ef78cc7a7cd7\\})| (\\{8a0699a0-09c3-4cf1-b38d-fec25441650c\\})$/","prefs":[],"schema":1517341295286,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1434759","why":"These add-ons use remote scripts to alter popular sites like Google or Amazon.","name":"Malicious remote script add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"32ffc62d-40c4-43ac-aa3f-7240978d0ad0","last_modified":1517439279474},{"guid":"/^({be5d0c88-571b-4d01-a27a-cc2d2b75868c})|({3908d078-e1db-40bf-9567-5845aa77b833})|({5b620343-cd69-49b8-a7ba-f9d499ee5d3d})|({6eee2d17-f932-4a43-a254-9e2223be8f32})|({e05ba06a-6d6a-4c51-b8fc-60b461ffecaf})|({a5808da1-5b4f-42f2-b030-161fd11a36f7})|({d355bee9-07f0-47d3-8de6-59b8eecba57b})|({a1f8e136-bce5-4fd3-9ed1-f260703a5582})$/","prefs":[],"schema":1517260691761,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.\n","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"70f37cc7-9f8a-4d0f-a881-f0c56934fa75","last_modified":1517260722621},{"guid":"/^({d78d27f4-9716-4f13-a8b6-842c455d6a46})|({bd5ba448-b096-4bd0-9582-eb7a5c9c0948})|({0b24cf69-02b8-407d-83db-e7af04fc1f3e})|({e08d85c5-4c0f-4ce3-9194-760187ce93ba})|({1c7d6d9e-325a-4260-8213-82d51277fc31})|({8a0699a0-09c3-4cf1-b38d-fec25441650c})|({1e68848a-2bb7-425c-81a2-524ab93763eb})$/","prefs":[],"schema":1517168490224,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"805ee80e-0929-4c92-93ed-062b98053f28","last_modified":1517260691755},{"guid":"/^({abec23c3-478f-4a5b-8a38-68ccd500ec42}|{a83c1cbb-7a41-41e7-a2ae-58efcb4dc2e4}|{62237447-e365-487e-8fc3-64ddf37bdaed}|{b12cfdc7-3c69-43cb-a3fb-38981b68a087}|{1a927d5b-42e7-4407-828a-fdc441d0daae}|{dd1cb0ec-be2a-432b-9c90-d64c824ac371}|{82c8ced2-e08c-4d6c-a12b-3e8227d7fc2a}|{87c552f9-7dbb-421b-8deb-571d4a2d7a21})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"c92f2a05-73eb-454e-9583-f6d2382d8bca","last_modified":1516829074251},{"guid":"/^({618baeb9-e694-4c7b-9328-69f35b6a8839}|{b91fcda4-88b0-4a10-9015-9365e5340563}|{04150f98-2d7c-4ae2-8979-f5baa198a577}|{4b1050c6-9139-4126-9331-30a836e75db9}|{1e6f5a54-2c4f-4597-aa9e-3e278c617d38}|{e73854da-9503-423b-ab27-fafea2fbf443}|{a2427e23-d349-4b25-b5b8-46960b218079}|{f92c1155-97b3-40f4-9d5b-7efa897524bb}|{c8e14311-4b2d-4eb0-9a6b-062c6912f50e}|{45621564-b408-4c29-8515-4cf1f26e4bc3}|{27380afd-f42a-4c25-b57d-b9012e0d5d48})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2d4fe65b-6c02-4461-baa8-dda52e688cf6","last_modified":1516829040469},{"guid":"/^({4dac7c77-e117-4cae-a9f0-6bd89e9e26ab}|{cc689da4-203f-4a0c-a7a6-a00a5abe74c5}|{0eb4672d-58a6-4230-b74c-50ca3716c4b0}|{06a71249-ef35-4f61-b2c8-85c3c6ee5617}|{5280684d-f769-43c9-8eaa-fb04f7de9199}|{c2341a34-a3a0-4234-90cf-74df1db0aa49}|{85e31e7e-3e3a-42d3-9b7b-0a2ff1818b33}|{b5a35d05-fa28-41b5-ae22-db1665f93f6b}|{1bd8ba17-b3ed-412e-88db-35bc4d8771d7}|{a18087bb-4980-4349-898c-ca1b7a0e59cd}|{488e190b-d1f6-4de8-bffb-0c90cc805b62})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9a3fd797-0ab8-4286-9a1b-2b6c97f9075b","last_modified":1516829006347},{"guid":"/^({f6df4ef7-14bd-43b5-90c9-7bd02943789c}|{ccb7b5d6-a567-40a2-9686-a097a8b583dd}|{9b8df895-fcdd-452a-8c46-da5be345b5bc}|{5cf77367-b141-4ba4-ac2a-5b2ca3728e81}|{ada56fe6-f6df-4517-9ed0-b301686a34cc}|{95c7ae97-c87e-4827-a2b7-7b9934d7d642}|{e7b978ae-ffc2-4998-a99d-0f4e2f24da82}|{115a8321-4414-4f4c-aee6-9f812121b446}|{bf153de7-cdf2-4554-af46-29dabfb2aa2d}|{179710ba-0561-4551-8e8d-1809422cb09f}|{9d592fd5-e655-461a-9b28-9eba85d4c97f})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"aae78cd5-6b26-472e-ab2d-db4105911250","last_modified":1516828973824},{"guid":"/^({30972e0a-f613-4c46-8c87-2e59878e7180}|{0599211f-6314-4bf9-854b-84cb18da97f8}|{4414af84-1e1f-449b-ac85-b79f812eb69b}|{2a8bec00-0ab0-4b4d-bd3d-4f59eada8fd8}|{bea8866f-01f8-49e9-92cd-61e96c05d288}|{046258c9-75c5-429d-8d5b-386cfbadc39d}|{c5d359ff-ae01-4f67-a4f7-bf234b5afd6e}|{fdc0601f-1fbb-40a5-84e1-8bbe96b22502}|{85349ea6-2b5d-496a-9379-d4be82c2c13d}|{640c40e5-a881-4d16-a4d0-6aa788399dd2}|{d42328e1-9749-46ba-b35c-cce85ddd4ace})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"750aa293-3742-46b5-8761-51536afecaef","last_modified":1516828938683},{"guid":"/^({d03b6b0f-4d44-4666-a6d6-f16ad9483593}|{767d394a-aa77-40c9-9365-c1916b4a2f84}|{a0ce2605-b5fc-4265-aa65-863354e85058}|{b7f366fa-6c66-46bf-8df2-797c5e52859f}|{4ad16913-e5cb-4292-974c-d557ef5ec5bb}|{3c3ef2a3-0440-4e77-9e3c-1ca8d48f895c}|{543f7503-3620-4f41-8f9e-c258fdff07e9}|{98363f8b-d070-47b6-acc6-65b80acac4f3}|{5af74f5a-652b-4b83-a2a9-f3d21c3c0010}|{484e0ba4-a20b-4404-bb1b-b93473782ae0}|{b99847d6-c932-4b52-9650-af83c9dae649})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"a29aed6f-6546-4fa2-8131-df5c9a5427af","last_modified":1516828911059},{"guid":"/^({2bb68b03-b528-4133-9fc4-4980fbb4e449}|{231e58ac-0f3c-460b-bb08-0e589360bec7}|{a506c5af-0f95-4107-86f8-3de05e2794c9}|{8886a262-1c25-490b-b797-2e750dd9f36b}|{65072bef-041f-492e-8a51-acca2aaeac70}|{6fa41039-572b-44a4-acd4-01fdaebf608d}|{87ba49bd-daba-4071-aedf-4f32a7e63dbe}|{95d58338-ba6a-40c8-93fd-05a34731dc0e}|{4cbef3f0-4205-4165-8871-2844f9737602}|{1855d130-4893-4c79-b4aa-cbdf6fee86d3}|{87dcb9bf-3a3e-4b93-9c85-ba750a55831a})$/","prefs":[],"schema":1516822896448,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5c092b0d-7205-43a1-aa75-b7a42372fb52","last_modified":1516828883523},{"guid":"/^({fce89242-66d3-4946-9ed0-e66078f172fc})|({0c4df994-4f4a-4646-ae5d-8936be8a4188})|({6cee30bc-a27c-43ea-ac72-302862db62b2})|({e08ebf0b-431d-4ed1-88bb-02e5db8b9443})$/","prefs":[],"schema":1516650096284,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1432560","why":"These are malicious add-ons that make it hard for the user to be removed.","name":"FF AntiVir Monitoring"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9dfeee42-e6a8-49e0-8979-0648f7368239","last_modified":1516744119329},{"guid":"/^(\\{1490068c-d8b7-4bd2-9621-a648942b312c\\})|(\\{d47ebc8a-c1ea-4a42-9ca3-f723fff034bd\\})|(\\{83d6f65c-7fc0-47d0-9864-a488bfcaa376\\})|(\\{e804fa4c-08e0-4dae-a237-8680074eba07\\})|(\\{ea618d26-780e-4f0f-91fd-2a6911064204\\})|(\\{ce93dcc7-f911-4098-8238-7f023dcdfd0d\\})|(\\{7eaf96aa-d4e7-41b0-9f12-775c2ac7f7c0\\})|(\\{b019c485-2a48-4f5b-be13-a7af94bc1a3e\\})|(\\{9b8a3057-8bf4-4a9e-b94b-867e4e71a50c\\})|(\\{eb3ebb14-6ced-4f60-9800-85c3de3680a4\\})|(\\{01f409a5-d617-47be-a574-d54325fe05d1\\})$/","prefs":[],"schema":1516394914836,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are a set of malicious add-ons that block the add-ons manager tab from opening so they can't be uninstalled.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5bf72f70-a611-4845-af3f-d4dabe8862b6","last_modified":1516394982586},{"guid":"/^(\\{ac06c6b2-3fd6-45ee-9237-6235aa347215\\})|(\\{d461cc1b-8a36-4ff0-b330-1824c148f326\\})|(\\{d1ab5ebd-9505-481d-a6cd-6b9db8d65977\\})|(\\{07953f60-447e-4f53-a5ef-ed060487f616\\})|(\\{2d3c5a5a-8e6f-4762-8aff-b24953fe1cc9\\})|(\\{f82b3ad5-e590-4286-891f-05adf5028d2f\\})|(\\{f96245ad-3bb0-46c5-8ca9-2917d69aa6ca\\})|(\\{2f53e091-4b16-4b60-9cae-69d0c55b2e78\\})|(\\{18868c3a-a209-41a6-855d-f99f782d1606\\})|(\\{47352fbf-80d9-4b70-9398-fb7bffa3da53\\})$/","prefs":[],"schema":1516311993443,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are a set of malicious add-ons that block the add-ons manager tab from opening so they can't be uninstalled.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"4ca8206f-bc2a-4428-9439-7f3142dc08db","last_modified":1516394914828},{"guid":"{5b0f6d3c-10fd-414c-a135-dffd26d7de0f}","prefs":[],"schema":1516131689499,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1430577","why":"This is a malicious add-on that executes remote scripts, redirects popular search URLs and tracks users.","name":"P Birthday"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"8088b39a-3e6d-4a17-a22f-3f95c0464bd6","last_modified":1516303320468},{"guid":"{1490068c-d8b7-4bd2-9621-a648942b312c}","prefs":[],"schema":1515267698296,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1428754","why":"This add-on is using a deceptive name and performing unwanted actions on users' systems.","name":"FF Safe Helper"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"674b6e19-f087-4706-a91d-1e723ed6f79e","last_modified":1515433728497},{"guid":"{dfa727cb-0246-4c5a-843a-e4a8592cc7b9}","prefs":[],"schema":1514922095288,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1426582","why":"Version 2.0.0 shipped with a hidden coin miner, which degrades performance in users who have it enabled. Version 1.2.3 currently available on AMO is not affected.","name":"Open With Adobe PDF Reader 2.0.0"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.0","minVersion":"2.0.0"}],"id":"455772a3-8360-4f5a-9a5f-a45b904d0b51","last_modified":1515007270887},{"guid":"{d03b6b0f-4d44-4666-a6d6-f16ad9483593}","prefs":[],"schema":1513366896461,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1425581","why":"This is a malicious add-on posing as a legitimate update.","name":"FF Guard Tool (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"10d9ce89-b8d4-4b53-b3d7-ecd192681f4e","last_modified":1513376470395},{"guid":"{7e907a15-0a4c-4ff4-b64f-5eeb8f841349}","prefs":[],"schema":1510083698490,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate update.","name":"Manual Update"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"f7569261-f575-4719-8202-552b20d013b0","last_modified":1510168860382},{"guid":"{3602008d-8195-4860-965a-d01ac4f9ca96}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"28c805a9-e692-4ef8-b3ae-14e085c19ecd","last_modified":1509120934909},{"guid":"{87010166-e3d0-4db5-a394-0517917201df}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"84dd8a02-c879-4477-8ea7-bf2f225b0940","last_modified":1509120881470},{"guid":"{8ab60777-e899-475d-9a4f-5f2ee02c7ea4}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"ccebab59-7190-4258-8faa-a0b752dd5301","last_modified":1509120831329},{"guid":"{368eb817-31b4-4be9-a761-b67598faf9fa}","prefs":[],"schema":1509046897080,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9abc7502-bd6f-40d7-b035-abe721345360","last_modified":1509120801043},{"guid":"fi@dictionaries.addons.mozilla.org","prefs":[],"schema":1508701297180,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1407147","why":"This add-on is causing frequent crashes in Firefox 56.","name":"Finnish spellchecker"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.1.0","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"56.0a1"}]}],"id":"22431713-a93b-40f4-8264-0b341b5f6454","last_modified":1508856488536},{"guid":"firefox@mega.co.nz","prefs":[],"schema":1506800496781,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1404290","why":"Add-on is causing tabs to load blank.","name":"Mega.nz"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.16.1","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"56.0a1"}]}],"id":"a84e6eba-4bc1-4416-b481-9b837d39f9f0","last_modified":1506963401477},{"guid":"@68eba425-7a05-4d62-82b1-1d6d5a51716b","prefs":[],"schema":1505072496256,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1398905","why":"Misleads users into thinking this is a security and privacy tool (also distributed on a site that makes it look like an official Mozilla product).","name":"SearchAssist Incognito"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0"}],"id":"595e0e53-b76b-4188-a160-66f29c636094","last_modified":1505211411253},{"guid":"{efda3854-2bd9-45a1-9766-49d7ff18931d}","prefs":[],"schema":1503344500341,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1392625","why":"Add-on injects remote code into privileged scope.","name":"Smart Referer"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.8.17.2","minVersion":"0"}],"id":"d83011de-67a4-479b-a778-916a7232095b","last_modified":1503411102265},{"guid":"@H99KV4DO-UCCF-9PFO-9ZLK-8RRP4FVOKD9O","prefs":[],"schema":1502483549048,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1340877","why":"This is a malicious add-on that is being installed silently.","name":"FF Adr (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5df16afc-c804-43c9-9de5-f1835403e5fb","last_modified":1502483601731},{"guid":"@DA3566E2-F709-11E5-8E87-A604BC8E7F8B","prefs":[],"schema":1502480491460,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1340877","why":"This is a malicious add-on that is being installed silently into users' systems.","name":"SimilarWeb (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"0a47a2f7-f07c-489b-bd39-88122a2dfe6a","last_modified":1502483549043},{"guid":"xdict@www.iciba.com","prefs":[],"schema":1501098091500,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1384497","why":"This add-on has been discontinued and is creating a prompt loop that blocks users from using Firefox.","name":"PowerWord Grab Word Extension"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.3.1","minVersion":"0"}],"id":"28736359-700e-4b61-9c50-0b533a6bac55","last_modified":1501187580933},{"guid":"{3B4DE07A-DE43-4DBC-873F-05835FF67DCE}","prefs":[],"schema":1496950889322,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1371392","why":"This add-on performs hidden actions that cause the users' systems to act as a botnet.","name":"The Safe Surfing (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"510bbd9b-b883-4837-90ab-8e353e27e1be","last_modified":1496951442076},{"guid":"WebProtection@360safe.com","prefs":[],"schema":1496846005095,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1336635","who":"All users of Firefox 52 and above who have this add-on installed.","why":"This add-on breaks the Firefox user interface starting with version 52.","name":"360 Internet Protection versions 5.0.0.1009 and lower"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"5.0.0.1009","minVersion":"0"}],"id":"e16408c3-4e08-47fd-85a9-3cbbce534e95","last_modified":1496849965060},{"guid":"html5@encoding","prefs":[],"schema":1496788543767,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1370847","who":"All users.","why":"This malicious add-on targets a certain user group and spies on them.","name":"HTML5 Encoding (Malicious), all versions"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"c806b01c-3352-4083-afd9-9a8ab6e00b19","last_modified":1496833261424},{"guid":"/^({95E84BD3-3604-4AAC-B2CA-D9AC3E55B64B}|{E3605470-291B-44EB-8648-745EE356599A}|{95E5E0AD-65F9-4FFC-A2A2-0008DCF6ED25}|{FF20459C-DA6E-41A7-80BC-8F4FEFD9C575}|{6E727987-C8EA-44DA-8749-310C0FBE3C3E}|{12E8A6C2-B125-479F-AB3C-13B8757C7F04}|{EB6628CF-0675-4DAE-95CE-EFFA23169743})$/","prefs":[],"schema":1494022576295,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1362585","why":"All of these add-ons have been identified as malware, and are being installed in Firefox globally, most likely via a malicious application installer.","name":"Malicious globally-installed add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3fd71895-7fc6-4f3f-aa22-1cbb0c5fd922","last_modified":1494024191520},{"guid":"@safesearchscoutee","prefs":[],"schema":1494013289942,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1362553","why":"This add-on intercepts queries sent to search engines and replaces them with its own, without user consent.","name":"SafeSearch Incognito (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"edad04eb-ea16-42f3-a4a7-20dded33cc37","last_modified":1494022568654},{"guid":"{0D2172E4-C5AE-465A-B80D-53A840275B5E}","prefs":[],"schema":1493332768943,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1359473","who":"All users of Thunderbird 52 and above, using a version of the Priority Switcher add-on before version 0.7","why":"This add-on is causing recurring startup crashes in Thunderbird.","name":"Priority Switcher for Thunderbird before version 0.7"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.6.999","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"52.0a1"}]}],"id":"8c8af415-46db-40be-a66e-38e3762493bd","last_modified":1493332986987},{"guid":"msktbird@mcafee.com","prefs":[],"schema":1493150718059,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1354912","why":"These versions of this add-on are known to cause frequent crashes in Thunderbird.","name":"McAfee Anti-Spam Thunderbird Extension 2.0 and lower"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"0"}]}],"id":"9e86d1ff-727a-45e3-9fb6-17f32666daf2","last_modified":1493332747360},{"guid":"/^(\\{11112503-5e91-4299-bf4b-f8c07811aa50\\})|(\\{501815af-725e-45be-b0f2-8f36f5617afc\\})$/","prefs":[],"schema":1491421290217,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1354045","why":"This add-on steals user credentials for popular websites from Facebook.","name":"Flash Player Updater (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c142360c-4f93-467e-9717-b638aa085d95","last_modified":1491472107658},{"guid":"fr@fbt.ovh","prefs":[],"schema":1490898754477,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351689","why":"Scam add-on that silently steals user credentials of popular websites","name":"Adobe Flash Player (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0f8344d0-8211-49a1-81be-c0084b3da9b1","last_modified":1490898787752},{"guid":"/^\\{(9321F452-96D5-11E6-BC3E-3769C7AD2208)|({18ED1ECA-96D3-11E6-A373-BD66C7AD2208})\\}$/","prefs":[],"schema":1490872899765,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351710","why":"These add-ons modify websites and add deceptive or abusive content","name":"Scamming add-ons (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d6425f24-8c9e-4c0a-89b4-6890fc68d5c9","last_modified":1490898748265},{"guid":"/^(test2@test\\.com)|(test3@test\\.com)|(mozilla_cc2\\.2@internetdownloadmanager\\.com)$/","prefs":[],"schema":1490557289817,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351095","who":"All users who have any of these add-ons installed.","why":"Old versions of the Internet Download Manager Integration add-on cause performance and stability problems in Firefox 53 and above.","name":"IDM Integration forks"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"53.0a1"}]}],"id":"9085fdba-8498-46a9-b9fd-4c7343a15c62","last_modified":1490653926191},{"guid":"mozilla_cc2@internetdownloadmanager.com","prefs":[],"schema":1489007018796,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1338832","who":"All users who have these versions of the add-on installed.","why":"Old versions of the Internet Download Manager Integration add-on cause performance and stability problems in Firefox 53 and above.","name":"IDM Integration"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"6.26.11","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"53.0a1"}]}],"id":"d33f6d48-a555-49dd-96ff-8d75473403a8","last_modified":1489514734167},{"guid":"InternetProtection@360safe.com","prefs":[],"schema":1489006712382,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1336635","who":"All Firefox users who have this add-on installed.","why":"This add-on breaks the Firefox user interface starting with version 52.","name":"360 Internet Protection"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"5.0.0.1002","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"52.0a1"}]}],"id":"89a61123-79a2-45d1-aec2-97afca0863eb","last_modified":1489006816246},{"guid":"{95E84BD3-3604-4AAC-B2CA-D9AC3E55B64B}","prefs":[],"schema":1487179851382,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1338690","who":"All users who have this add-on installed.","why":"This is a malicious add-on that is silently installed in users' systems.","name":"youtube adblock (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"04b25e3d-a725-493e-be07-cbd74fb37ea7","last_modified":1487288975999},{"guid":"ext@alibonus.com","prefs":[],"schema":1485297431051,"blockID":"i1524","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1333471","who":"All Firefox users who have these versions installed.","why":"Versions 1.20.9 and lower of this add-on contain critical security issues.","name":"Alibonus 1.20.9 and lower","created":"2017-01-24T22:45:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.20.9","minVersion":"0","targetApplication":[]}],"id":"a015d5a4-9184-95db-0c74-9262af2332fa","last_modified":1485301116629},{"guid":"{a0d7ccb3-214d-498b-b4aa-0e8fda9a7bf7}","prefs":[],"schema":1485295513652,"blockID":"i1523","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1314332","who":"All Firefox users who have these versions of the Web of Trust add-on installed.","why":"Versions 20170120 and lower of the Web of Trust add-on send excessive user data to its service, which has been reportedly shared with third parties without sufficient sanitization. These versions are also affected by a vulnerability that could lead to unwanted remote code execution.","name":"Web of Trust 20170120 and lower","created":"2017-01-24T22:01:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"20170120","minVersion":"0","targetApplication":[]}],"id":"2224c139-9b98-0900-61c1-04031de11ad3","last_modified":1485297214072},{"guid":"/^(ciscowebexstart1@cisco\\.com|ciscowebexstart_test@cisco\\.com|ciscowebexstart@cisco\\.com|ciscowebexgpc@cisco\\.com)$/","prefs":[],"schema":1485212610474,"blockID":"i1522","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1333225","who":"All Firefox users who have any Cisco WebEx add-ons installed.","why":"A critical security vulnerability has been discovered in Cisco WebEx add-ons that enable malicious websites to execute code on the user's system.","name":"Cisco WebEx add-ons","created":"2017-01-23T22:55:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.1","minVersion":"1.0.0","targetApplication":[]}],"id":"30368779-1d3b-490a-0a34-253085af7754","last_modified":1485215014902},{"guid":"{de71f09a-3342-48c5-95c1-4b0f17567554}","prefs":[],"schema":1484335370642,"blockID":"i1493","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1329654","who":"All users who have this add-on installed.","why":"This is a malicious add-on that is installed using a fake name. It changes search and homepage settings.","name":"Search for Firefox Convertor (malware)","created":"2017-01-12T22:17:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.3.9","minVersion":"0","targetApplication":[]}],"id":"d6ec9f54-9945-088e-ba68-40117eaba24e","last_modified":1484867614757},{"guid":"googlotim@gmail.com","prefs":[],"schema":1483389810787,"blockID":"i1492","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1328594","who":"All users who have Savogram version 1.3.2 installed. Version 1.3.1 doesn't have this problem and can be installed from the add-on page. Note that this is an older version, so affected users won't be automatically updated to it. New versions should correct this problem if they become available.","why":"Version 1.3.2 of this add-on loads remote code and performs DOM injection in an unsafe manner.","name":"Savogram 1.3.2","created":"2017-01-05T19:58:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.2","minVersion":"1.3.2","targetApplication":[]}],"id":"0756ed76-7bc7-ec1e-aba5-3a9fac2107ba","last_modified":1483646608603},{"guid":"support@update-firefox.com","prefs":[],"schema":1483387107003,"blockID":"i21","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=629717","who":"All users of the add-on in all Mozilla applications.","why":"This add-on is adware/spyware masquerading as a Firefox update mechanism.","name":"Browser Update (spyware)","created":"2011-01-31T16:23:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dfb06be8-3594-28e4-d163-17e27119f15d","last_modified":1483389809169},{"guid":"{2224e955-00e9-4613-a844-ce69fccaae91}","prefs":[],"schema":1483387107003,"blockID":"i7","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=512406","who":"All users of Internet Saving Optimizer for all Mozilla applications.","why":"This add-on causes a high volume of Firefox crashes and is considered malware.","name":"Internet Saving Optimizer (extension)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9efb796-97c2-6434-d28f-acc83436f8e5","last_modified":1483389809147},{"guid":"supportaccessplugin@gmail.com","prefs":[],"schema":1483387107003,"blockID":"i43","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=693673","who":"All users with Firefox Access Plugin installed","why":"This add-on is spyware that reports all visited websites to a third party with no user value.","name":"Firefox Access Plugin (spyware)","created":"2011-10-11T11:24:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ed230a4-e174-262a-55ab-0c33f93a2529","last_modified":1483389809124},{"guid":"{8CE11043-9A15-4207-A565-0C94C42D590D}","prefs":[],"schema":1483387107003,"blockID":"i10","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=541302","who":"All users of this add-on in all Mozilla applications.","why":"This add-on secretly hijacks all search results in most major search engines and masks as a security add-on.","name":"Internal security options editor (malware)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e2e0ac09-6d68-75f5-2424-140f51904876","last_modified":1483389809102},{"guid":"youtube@youtube2.com","prefs":[],"schema":1483387107003,"blockID":"i47","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=713050","who":"All users with any version of Free Cheesecake Factory installed on any Mozilla product.","why":"This add-on hijacks your Facebook account.","name":"Free Cheesecake Factory (malware)","created":"2011-12-22T13:11:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"85f5c1db-433b-bee3-2a3b-325165cacc6e","last_modified":1483389809079},{"guid":"admin@youtubespeedup.com","prefs":[],"schema":1483387107003,"blockID":"i48","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=714221","who":"All users with any version of Youtube Speed UP! installed on any Mozilla product.","why":"This add-on hijacks your Facebook account.","name":"Youtube Speed UP! (malware)","created":"2011-12-29T19:48:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a93922c4-8a8a-5230-8f76-76fecb0653b6","last_modified":1483389809057},{"guid":"{E8E88AB0-7182-11DF-904E-6045E0D72085}","prefs":[],"schema":1483387107003,"blockID":"i13","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=578085","who":"All users of this add-on for all Mozilla applications.","why":"This add-on intercepts website login credentials and is malware. For more information, please read our security announcement.","name":"Mozilla Sniffer (malware)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ebbd6de9-fc8a-3e5b-2a07-232bee589c7c","last_modified":1483389809035},{"guid":"sigma@labs.mozilla","prefs":[],"schema":1483387107003,"blockID":"i44","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=690819","who":"All users of Lab Kit in all versions of Firefox.","why":"The Lab Kit add-on has been retired due to compatibility issues with Firefox 7 and future Firefox browser releases. You can still install Mozilla Labs add-ons individually.\r\n\r\nFor more information, please read this announcement.","name":"Mozilla Labs: Lab Kit","created":"2011-10-11T11:51:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d614e9cd-220f-3a19-287b-57e122f8c4b5","last_modified":1483389809012},{"guid":"/^(jid0-S9kkzfTvEmC985BVmf8ZOzA5nLM@jetpack|jid1-qps14pkDB6UDvA@jetpack|jid1-Tsr09YnAqIWL0Q@jetpack|shole@ats.ext|{38a64ef0-7181-11e3-981f-0800200c9a66}|eochoa@ualberta.ca)$/","prefs":[],"schema":1483376308298,"blockID":"i1424","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:22:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0699488d-2a19-6735-809e-f229849fe00b","last_modified":1483378113482},{"guid":"pink@rosaplugin.info","prefs":[],"schema":1482945809444,"blockID":"i84","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743484","who":"All Firefox users who have this add-on installed","why":"Add-on acts like malware and performs user actions on Facebook without their consent.","name":"Facebook Rosa (malware)","created":"2012-04-09T10:13:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"66ad8de9-311d-076c-7356-87fde6d30d8f","last_modified":1482945810971},{"guid":"videoplugin@player.com","prefs":[],"schema":1482945809444,"blockID":"i90","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=752483","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Flash Player update. It can hijack Google searches and Facebook accounts.","name":"FlashPlayer 11 (malware)","created":"2012-05-07T08:58:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d25943f1-39ef-b9ec-ab77-baeef3498365","last_modified":1482945810949},{"guid":"youtb3@youtb3.com","prefs":[],"schema":1482945809444,"blockID":"i60","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=723753","who":"All Firefox users who have this extension installed.","why":"Malicious extension installed under false pretenses.","name":"Video extension (malware)","created":"2012-02-02T16:38:41Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cae3093f-a7b3-5352-a264-01dbfbf347ce","last_modified":1482945810927},{"guid":"{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}","prefs":[],"schema":1482945809444,"blockID":"i82","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743012","who":"All Firefox users who have installed this add-on.","why":"This add-on maliciously manipulates Facebook and is installed under false pretenses.","name":"Face Plus (malware)","created":"2012-04-09T10:04:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"09319ab3-55e7-fec1-44e0-84067d014b9b","last_modified":1482945810904},{"guid":"cloudmask@cloudmask.com","prefs":[],"schema":1482945809444,"blockID":"i1233","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1280431","who":"Any user who has version 2.0.788, or earlier, installed.","why":"These versions of the add-on (before 2.0.788) execute code from a website in a privileged local browser context, potentially allowing dangerous, unreviewed, actions to affect the user's computer. This is fixed in later versions.","name":"CloudMask","created":"2016-06-17T14:31:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.788","minVersion":"0","targetApplication":[]}],"id":"2a8b40c7-a1d2-29f4-b7d7-ccfc5066bae1","last_modified":1482945810881},{"guid":"{95ff02bc-ffc6-45f0-a5c8-619b8226a9de}","prefs":[],"schema":1482945809444,"blockID":"i105","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.\r\n","name":"Eklenti D\u00fcnyas\u0131 (malware)","created":"2012-06-08T14:34:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"afbbc08d-2414-f51e-fdb8-74c0a2d90323","last_modified":1482945810858},{"guid":"{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}","prefs":[],"schema":1482945809444,"blockID":"i77","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=738419","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware that is installed under false pretenses as an Adobe plugin.","name":"Adobe Flash (malware)","created":"2012-03-22T14:39:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81753a93-382d-5f9d-a4ca-8a21b679ebb1","last_modified":1482945810835},{"guid":"youtube@youtube3.com","prefs":[],"schema":1482945809444,"blockID":"i57","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722823","who":"All Firefox users that have installed this add-on.","why":"Malware installed on false pretenses.","name":"Divx 2012 Plugin (malware)","created":"2012-01-31T13:54:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4a93a0eb-a513-7272-6199-bc4d6228ff50","last_modified":1482945810811},{"guid":"{392e123b-b691-4a5e-b52f-c4c1027e749c}","prefs":[],"schema":1482945809444,"blockID":"i109","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=769781","who":"All Firefox users who have this add-on installed.","why":"This add-on pretends to be developed by Facebook and injects scripts that manipulate users' Facebook accounts.","name":"Zaman Tuneline Hay\u0131r! (malware)","created":"2012-06-29T13:20:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9a805aa-cae7-58d6-5a53-2af4442e4cf6","last_modified":1482945810788},{"guid":"msntoolbar@msn.com","prefs":[],"schema":1482945809444,"blockID":"i18","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of Bing Bar 6.0 and older for all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Bing Bar","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"6.*","minVersion":" 0","targetApplication":[]}],"id":"9b2f2039-b997-8993-d6dc-d881bc1ca7a1","last_modified":1482945810764},{"guid":"yasd@youasdr3.com","prefs":[],"schema":1482945809444,"blockID":"i104","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.\r\n","name":"Play Now (malware)","created":"2012-06-08T14:33:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8a352dff-d09d-1e78-7feb-45dec7ace5a5","last_modified":1482945810740},{"guid":"fdm_ffext@freedownloadmanager.org","prefs":[],"schema":1482945809444,"blockID":"i2","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=408445","who":"Users of Firefox 3 and later with versions 1.0 through 1.3.1 of Free Download Manager","why":"This add-on causes a high volume of crashes.","name":"Free Download Manager","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.1","minVersion":"1.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.0a1"}]}],"id":"fc46f8e7-0489-b90f-a373-d93109479ca5","last_modified":1482945810393},{"guid":"flash@adobe.com","prefs":[],"schema":1482945809444,"blockID":"i56","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722526","who":"All Firefox users who have this add-on installed.","why":"This add-on poses as an Adobe Flash update and injects malicious scripts into web pages. It hides itself in the Add-ons Manager.","name":"Adobe Flash Update (malware)","created":"2012-01-30T15:41:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"696db959-fb0b-8aa4-928e-65f157cdd77a","last_modified":1482945810371},{"guid":"youtubeer@youtuber.com","prefs":[],"schema":1482945809444,"blockID":"i66","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=726787","who":"All Firefox users who have installed this add-on.","why":"Add-on behaves maliciously, and is installed under false pretenses.","name":"Plug VDS (malware)","created":"2012-02-13T15:44:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0878ce4e-b476-ffa3-0e06-21a65b7917a1","last_modified":1482945810348},{"guid":"{B13721C7-F507-4982-B2E5-502A71474FED}","prefs":[],"schema":1482945809444,"blockID":"i8","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=627278","who":"Users of all versions of the original Skype Toolbar in all versions of Firefox.","why":"This add-on causes a high volume of Firefox crashes and introduces severe performance issues. Please update to the latest version. For more information, please read our announcement.","name":"Original Skype Toolbar","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5a320611-59a3-0eee-bb30-9052be870e00","last_modified":1482945810326},{"guid":"yslow@yahoo-inc.com","prefs":[],"schema":1482945809444,"blockID":"i11","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=542686","who":"Users of YSlow version 2.0.5 for Firefox 3.5.7 and later.","why":"This add-on causes a high volume of Firefox crashes and other stability issues. Users should update to the latest version.","name":"YSlow","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.5","minVersion":"2.0.5","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.5.7"}]}],"id":"a9b34e8f-45ce-9217-b791-98e094c26352","last_modified":1482945810303},{"guid":"youtube@youtuber.com","prefs":[],"schema":1482945809444,"blockID":"i63","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=724691","who":"All Firefox users who have installed this add-on.","why":"Installs under false pretenses and delivers malware.","name":"Mozilla Essentials (malware)","created":"2012-02-06T15:39:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"18216e6f-9d70-816f-4d4c-63861f43ff3c","last_modified":1482945810281},{"guid":"flash@adobee.com","prefs":[],"schema":1482945809444,"blockID":"i83","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743497","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware installed under false pretenses.","name":"FlashPlayer 11 (malware)","created":"2012-04-09T10:08:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"09bb4661-331c-f7ba-865b-9e085dc437af","last_modified":1482945810259},{"guid":"youtube@2youtube.com","prefs":[],"schema":1482945809444,"blockID":"i71","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=730399","who":"All Firefox users who have installed this add-on.","why":"Extension is malware, installed under false pretenses.","name":"YouTube extension (malware)","created":"2012-02-27T10:23:23Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5d389c1f-b3a0-b06f-6ffb-d1e8aa055e3c","last_modified":1482945810236},{"guid":"webmaster@buzzzzvideos.info","prefs":[],"schema":1482945809444,"blockID":"i58","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722844","who":"All Firefox users who have installed this add-on.","why":"Malware add-on that is installed under false pretenses.","name":"Buzz Video (malware)","created":"2012-01-31T14:51:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7aab105-e2c2-42f5-d9be-280eb9c0c8f7","last_modified":1482945810213},{"guid":"play5@vide04flash.com","prefs":[],"schema":1482945809444,"blockID":"i92","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=755443","who":"All Firefox users who have this add-on installed.","why":"This add-on impersonates a Flash Player update (poorly), and inserts malicious scripts into Facebook.","name":"Lastest Flash PLayer (malware)","created":"2012-05-15T13:27:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7190860e-fc1f-cd9f-5d25-778e1e9043b2","last_modified":1482945810191},{"guid":"support3_en@adobe122.com","prefs":[],"schema":1482945809444,"blockID":"i97","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759164","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as the Flash Player plugin.","name":"FlashPlayer 11 (malware)","created":"2012-05-28T13:42:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"decf93a1-2bb0-148c-a1a6-10b3757b554b","last_modified":1482945810168},{"guid":"a1g0a9g219d@a1.com","prefs":[],"schema":1482945809444,"blockID":"i73","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=736275","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as Flash Player. It steals user cookies and sends them to a remote location.","name":"Flash Player (malware)","created":"2012-03-15T15:03:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6dd66b43-897d-874a-2227-54e240b8520f","last_modified":1482945810146},{"guid":"ghostviewer@youtube2.com","prefs":[],"schema":1482945809444,"blockID":"i59","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=723683","who":"All Firefox users who have installed this add-on.","why":"Malicious add-on that automatically posts to Facebook.","name":"Ghost Viewer (malware)","created":"2012-02-02T16:32:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"06dfe833-8c3d-90ee-3aa8-37c3c28f7c56","last_modified":1482945810123},{"guid":"{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}","prefs":[],"schema":1482945809444,"blockID":"i19","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=621660","who":"Users of Stylish version 1.1b1 for Firefox.","why":"Version 1.1b1 of this add-on causes compatibility issues with Firefox. Users should update to the latest version.","name":"Stylish","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.1b1","minVersion":"1.1b1","targetApplication":[]}],"id":"aaea37e1-ff86-4565-8bd5-55a6bf942791","last_modified":1482945810101},{"guid":"kdrgun@gmail.com","prefs":[],"schema":1482945809444,"blockID":"i103","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.","name":"Timeline Kapat (malware)","created":"2012-06-08T14:32:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a9a46ab2-2f56-1046-201c-5faa3435e248","last_modified":1482945810078},{"guid":"youtube2@youtube2.com","prefs":[],"schema":1482945809444,"blockID":"i67","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=728476","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware, installed under false pretenses.","name":"Youtube Online (malware)","created":"2012-02-18T09:10:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"14650ece-295b-a667-f9bc-a3d973e2228c","last_modified":1482945810055},{"guid":"masterfiler@gmail.com","prefs":[],"schema":1482945809444,"blockID":"i12","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=542081","who":"All users of this add-on for all Mozilla applications.","why":"This add-on is malware and attempts to install a Trojan on the user's computer.","name":"Master File (malware)","created":"2010-02-05T15:01:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a256d79d-5af8-92e9-a29d-350adf822efe","last_modified":1482945810032},{"guid":"{847b3a00-7ab1-11d4-8f02-006008948af5}","prefs":[],"schema":1482945809444,"blockID":"i9","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=531047","who":"Users of Enigmail versions older than 0.97a for Thunderbird 3 and later.","why":"This add-on causes a high volume of crashes and other stability issues. Users should update Enigmail.","name":"Enigmail","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.97a","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"3.0pre"}]}],"id":"115f46b6-059d-202a-4373-2ca79b096347","last_modified":1482945810003},{"guid":"mozilla_cc@internetdownloadmanager.com","prefs":[],"schema":1482945809444,"blockID":"i14","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=578443","who":"Users of Firefox 4 and later with Internet Download Manager version 6.9.8 and older.","why":"This add-on causes a high volume of crashes and has other stability issues.","name":"Internet Download Manager","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"6.9.8","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"773ffcfb-75d1-081d-7431-ebe3fa5dbb44","last_modified":1482945809979},{"guid":"admin@youtubeplayer.com","prefs":[],"schema":1482945809444,"blockID":"i51","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=717165","who":"All Firefox users with this extension installed.","why":"This add-on is malware, doing nothing more than inserting advertisements into websites through iframes.","name":"Youtube player (malware)","created":"2012-01-18T14:34:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"16b2ce94-88db-0d79-33fc-a93070ceb509","last_modified":1482945809957},{"guid":"personas@christopher.beard","prefs":[],"schema":1482945809444,"blockID":"i15","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=590978","who":"All users of Personas Plus 1.6 in all versions of Firefox.","why":"This version of Personas Plus is incompatible with certain Firefox functionality and other add-ons. Users should upgrade to the latest version.","name":"Personas Plus","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.6","minVersion":"1.6","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"3.6.*","minVersion":"3.6"}]}],"id":"e36479c6-ca00-48d4-4fd9-ec677fd032da","last_modified":1482945809934},{"guid":"youtubeee@youtuber3.com","prefs":[],"schema":1482945809444,"blockID":"i96","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=758503","who":"All Firefox users who have installed this add-on.","why":"This is a malicious add-on that is disguised as a DivX plugin.","name":"Divx 2012 Plugins (malware)","created":"2012-05-25T09:26:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f01be9cb-5cf2-774a-a4d7-e210a24db5b9","last_modified":1482945809912},{"guid":"{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}","prefs":[],"schema":1482945809444,"blockID":"i17","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of version 2.2 of this add-on in all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Default Manager (Microsoft)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.2","minVersion":"2.2","targetApplication":[]}],"id":"38be28ac-2e30-37fa-4332-852a55fafb43","last_modified":1482945809886},{"guid":"{68b8676b-99a5-46d1-b390-22411d8bcd61}","prefs":[],"schema":1482945809444,"blockID":"i93","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=755635","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that post content on Facebook accounts and steals user data.","name":"Zaman T\u00fcnelini Kald\u0131r! (malware)","created":"2012-05-16T10:44:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"733aff15-9b1f-ec04-288f-b78a55165a1c","last_modified":1482945809863},{"guid":"applebeegifts@mozilla.doslash.org","prefs":[],"schema":1482945809444,"blockID":"i54","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=721562","who":"All Firefox users that install this add-on.","why":"Add-on is malware installed under false pretenses.","name":"Applebees Gift Card (malware)","created":"2012-01-26T16:17:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1372c8ab-5452-745a-461a-aa78e3e12c4b","last_modified":1482945809840},{"guid":"activity@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i65","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=726803","who":"All Firefox users who have installed this add-on.","why":"Add-on behaves maliciously and poses as an official Facebook add-on.","name":"Facebook extension (malware)","created":"2012-02-13T15:41:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"79ad1c9b-0828-7823-4574-dd1cdd46c3d6","last_modified":1482945809437},{"guid":"jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack","prefs":[],"schema":1482945112982,"blockID":"i62","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=724650","who":"All Firefox users who have installed this add-on.","why":"Add-on is installed under false pretenses and delivers malware.","name":"YouTube extension (malware)","created":"2012-02-06T14:46:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5ae1e642-b53c-54c0-19e7-5562cfdac3a3","last_modified":1482945809415},{"guid":"{B7082FAA-CB62-4872-9106-E42DD88EDE45}","prefs":[],"schema":1482945112982,"blockID":"i25","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=637542","who":"Users of McAfee SiteAdvisor below version 3.3.1 for Firefox 4.\r\n\r\nUsers of McAfee SiteAdvisor 3.3.1 and below for Firefox 5 and higher.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"McAfee SiteAdvisor","created":"2011-03-14T15:53:07Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.3.0.*","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1"}]}],"id":"c950501b-1f08-2ab2-d817-7c664c0d16fe","last_modified":1482945809393},{"guid":"{B7082FAA-CB62-4872-9106-E42DD88EDE45}","prefs":[],"schema":1482945112982,"blockID":"i38","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=660111","who":"Users of McAfee SiteAdvisor below version 3.3.1 for Firefox 4.\r\n\r\nUsers of McAfee SiteAdvisor 3.3.1 and below for Firefox 5 and higher.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"McAfee SiteAdvisor","created":"2011-05-27T13:55:02Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"3.3.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"5.0a1"}]}],"id":"f11de388-4511-8d06-1414-95d3b2b122c5","last_modified":1482945809371},{"guid":"{3f963a5b-e555-4543-90e2-c3908898db71}","prefs":[],"schema":1482945112982,"blockID":"i6","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=527135","who":"Users of AVG SafeSearch version 8.5 and older for all Mozilla applications.","why":"This add-on causes a high volume of crashes and causes other stability issues.","name":"AVG SafeSearch","created":"2009-06-17T13:12:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"8.5","minVersion":"0","targetApplication":[]}],"id":"0d6f7d4c-bf5d-538f-1ded-ea4c6b775617","last_modified":1482945809348},{"guid":"langpack-vi-VN@firefox.mozilla.org","prefs":[],"schema":1482945112982,"blockID":"i3","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=432406","who":"Users of Vietnamese Language Pack version 2.0 for all Mozilla applications.","why":"Corrupted files. For more information, please see this blog post.","name":"Vietnamese Language Pack","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0","minVersion":"2.0","targetApplication":[]}],"id":"51d4b581-d21c-20a1-6147-b17c3adc7867","last_modified":1482945809326},{"guid":"youtube@youtube7.com","prefs":[],"schema":1482945112982,"blockID":"i55","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=721646","who":"All Firefox users with this add-on installed.","why":"This is malware posing as video software.","name":"Plugin Video (malware)","created":"2012-01-27T09:39:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"08ceedf5-c7c1-f54f-db0c-02f01f0e319a","last_modified":1482945809304},{"guid":"crossriderapp3924@crossrider.com","prefs":[],"schema":1482945112982,"blockID":"i76","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=738282","who":"All Firefox users who have installed this add-on.","why":"This add-on compromises Facebook privacy and security and spams friends lists without user intervention.","name":"Fblixx (malware)","created":"2012-03-22T10:38:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39d0a019-62fb-837b-1f1f-6831e56442b5","last_modified":1482945809279},{"guid":"{45147e67-4020-47e2-8f7a-55464fb535aa}","prefs":[],"schema":1482945112982,"blockID":"i86","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=748993","who":"All Firefox users who have this add-on installed.","why":"This add-on injects scripts into Facebook and performs malicious activity.","name":"Mukemmel Face+","created":"2012-04-25T16:33:21Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"960443f9-cf48-0b71-1ff2-b8c34a3411ea","last_modified":1482945809255},{"guid":"{4B3803EA-5230-4DC3-A7FC-33638F3D3542}","prefs":[],"schema":1482945112982,"blockID":"i4","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=441649","who":"Users of Firefox 3 and later with version 1.2 of Crawler Toolbar","why":"This add-on causes a high volume of crashes.","name":"Crawler Toolbar","created":"2008-07-08T10:23:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2","minVersion":"1.2","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.0a1"}]}],"id":"a9818d53-3a6a-8673-04dd-2a16f5644215","last_modified":1482945809232},{"guid":"flashupdate@adobe.com","prefs":[],"schema":1482945112982,"blockID":"i68","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722526","who":"All Firefox users who have this add-on installed.","why":"Add-on is malware, installed under false pretenses.","name":"Flash Update (malware)","created":"2012-02-21T13:55:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ba5b46e-790d-5af2-9580-a5f1e6e65522","last_modified":1482945809208},{"guid":"plugin@youtubeplayer.com","prefs":[],"schema":1482945112982,"blockID":"i127","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=783356","who":"All users who have this add-on installed.","why":"This add-on tries to pass as a YouTube player and runs malicious scripts on webpages.","name":"Youtube Facebook Player (malware)","created":"2012-08-16T13:03:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"17a8bece-e2df-a55d-8a72-95faff028b83","last_modified":1482945809185},{"guid":"GifBlock@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i79","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=739482","who":"All Firefox users who have installed this extension.","why":"This extension is malicious and is installed under false pretenses.","name":"Facebook Essentials (malware)","created":"2012-03-27T10:53:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"728451e8-1273-d887-37e9-5712b1cc3bff","last_modified":1482945809162},{"guid":"ff-ext@youtube","prefs":[],"schema":1482945112982,"blockID":"i52","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=719296","who":"All Firefox users that have this add-on installed.","why":"This add-on poses as a YouTube player while posting spam into Facebook account.","name":"Youtube player (malware)","created":"2012-01-19T08:26:35Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cd2dd72a-dd52-6752-a0cd-a4b312fd0b65","last_modified":1482945809138},{"guid":"ShopperReports@ShopperReports.com","prefs":[],"schema":1482945112982,"blockID":"i22","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=630191","who":"Users of Shopper Reports version 3.1.22.0 in Firefox 4 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"Shopper Reports","created":"2011-02-09T17:03:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.1.22.0","minVersion":"3.1.22.0","targetApplication":[]}],"id":"f26b049c-d856-750f-f050-996e6bec7cbb","last_modified":1482945809115},{"guid":"{27182e60-b5f3-411c-b545-b44205977502}","prefs":[],"schema":1482945112982,"blockID":"i16","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of version 1.0 of this add-on in all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Search Helper Extension (Microsoft)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0","minVersion":"1.0","targetApplication":[]}],"id":"2655f230-11f3-fe4c-7c3d-757d37d5f9a5","last_modified":1482945809092},{"guid":"{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}","prefs":[],"schema":1482945112982,"blockID":"i46","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=712369","who":"Users of all versions of Nectar Search Toolbar in Firefox 9.","why":"This add-on causes crashes and other stability issues in Firefox.","name":"Nectar Search Toolbar","created":"2011-12-20T11:38:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"9.0","minVersion":"9.0a1"}]}],"id":"b660dabd-0dc0-a55c-4b86-416080b345d9","last_modified":1482945809069},{"guid":"support@daemon-tools.cc","prefs":[],"schema":1482945112982,"blockID":"i5","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=459850","who":"Users of Daemon Tools Toolbar version 1.0.0.5 and older for all Mozilla applications.","why":"This add-on causes a high volume of crashes.","name":"Daemon Tools Toolbar","created":"2009-02-13T18:39:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.0.5","minVersion":"0","targetApplication":[]}],"id":"8cabafd3-576a-b487-31c8-ab59e0349a0e","last_modified":1482945809045},{"guid":"{a3a5c777-f583-4fef-9380-ab4add1bc2a8}","prefs":[],"schema":1482945112982,"blockID":"i53","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=719605","who":"All users of Firefox with this add-on installed.","why":"This add-on is being offered as an online movie viewer, when it reality it only inserts scripts and ads into known sites.","name":"Peliculas-FLV (malware)","created":"2012-01-19T15:58:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0.3","minVersion":"2.0.3","targetApplication":[]}],"id":"07bc0962-60da-087b-c3ab-f2a6ab84d81c","last_modified":1482945809021},{"guid":"royal@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i64","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=725777","who":"All Firefox users who have installed this add-on.","why":"Malicious add-on posing as a Facebook tool.","name":"Facebook ! (malware)","created":"2012-02-09T13:24:23Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dd1d2623-0d15-c93e-8fbd-ba07b0299a44","last_modified":1482945808997},{"guid":"{28bfb930-7620-11e1-b0c4-0800200c9a66}","prefs":[],"schema":1482945112982,"blockID":"i108","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=766852","who":"All Firefox user who have this add-on installed.","why":"This is malware disguised as an Adobe product. It spams Facebook pages.","name":"Aplicativo (malware)","created":"2012-06-21T09:24:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"908dc4fb-ebc9-cea1-438f-55e4507ba834","last_modified":1482945808973},{"guid":"socialnetworktools@mozilla.doslash.org","prefs":[],"schema":1482945112982,"blockID":"i78","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=739441","who":"All Firefox users who have installed this add-on.","why":"This add-on hijacks the Facebook UI and adds scripts to track users.","name":"Social Network Tools (malware)","created":"2012-03-26T16:46:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1064cd25-3b87-64bb-b0a6-2518ad281574","last_modified":1482945808950},{"guid":"youtubeeing@youtuberie.com","prefs":[],"schema":1482945112982,"blockID":"i98","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759663","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Youtube add-on.","name":"Youtube Video Player (malware)","created":"2012-05-30T09:30:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3484f860-56e1-28e8-5a70-cdcd5ab9d6ee","last_modified":1482945808927},{"guid":"{3a12052a-66ef-49db-8c39-e5b0bd5c83fa}","prefs":[],"schema":1482945112982,"blockID":"i101","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=761874","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Facebook timeline remover.","name":"Timeline Remove (malware)","created":"2012-06-05T18:37:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b01b321b-6628-7166-bd15-52f21a04d8bd","last_modified":1482945808904},{"guid":"pfzPXmnzQRXX6@2iABkVe.com","prefs":[],"schema":1482945112982,"blockID":"i99","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759950","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware disguised as a Flash Player update.","name":"Flash Player (malware)","created":"2012-05-30T17:10:18Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"29cc4abc-4f52-01f1-eb0b-cad84ba4db13","last_modified":1482945808881},{"guid":"/^(@pluginscribens_firefox|extension@vidscrab.com|firefox@jjj.ee|firefox@shop-reward.de|FxExtPasteNGoHtk@github.lostdj|himanshudotrai@gmail.com|jid0-bigoD0uivzAMmt07zrf3OHqa418@jetpack|jid0-iXbAR01tjT2BsbApyS6XWnjDhy8@jetpack)$/","prefs":[],"schema":1482341309012,"blockID":"i1423","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:21:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a58a2836-e4e7-74b5-c109-fa3d41e9ed56","last_modified":1482343886390},{"guid":"/^(pdftoword@addingapps.com|jid0-EYTXLS0GyfQME5irGbnD4HksnbQ@jetpack|jid1-ZjJ7t75BAcbGCX@jetpack)$/","prefs":[],"schema":1482341309012,"blockID":"i1425","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:23:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"150e639f-c832-63d0-a775-59313b2e1bf9","last_modified":1482343886365},{"guid":"{cc8f597b-0765-404e-a575-82aefbd81daf}","prefs":[],"schema":1480349193877,"blockID":"i380","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866332","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts and performs unwanted actions on behalf of the user.","name":"Update My Browser (malware)","created":"2013-06-19T13:03:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4950d7aa-c602-15f5-a7a2-d844182d5cbd","last_modified":1480349217152},{"guid":"extension@FastFreeConverter.com","prefs":[],"schema":1480349193877,"blockID":"i470","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"649dd933-debf-69b7-020f-496c2c9f99c8","last_modified":1480349217071},{"guid":"59D317DB041748fdB89B47E6F96058F3@jetpack","prefs":[],"schema":1480349193877,"blockID":"i694","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053540","who":"All Firefox users who have this add-ons installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This is a suspicious add-on that appears to be installed without user consent, in violation of the Add-on Guidelines.","name":"JsInjectExtension","created":"2014-08-21T13:46:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"75692bd4-18e5-a9be-7ec3-9327e159ef68","last_modified":1480349217005},{"guid":"/^({bfec236d-e122-4102-864f-f5f19d897f5e}|{3f842035-47f4-4f10-846b-6199b07f09b8}|{92ed4bbd-83f2-4c70-bb4e-f8d3716143fe})$/","prefs":[],"schema":1480349193877,"blockID":"i527","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and uses multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:13:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d68dd97-7965-0a84-8ca7-435aac3c8040","last_modified":1480349216927},{"guid":"support@vide1flash2.com","prefs":[],"schema":1480349193877,"blockID":"i246","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=830159","who":"All Firefox users who have this add-on installed.","why":"This is an add-on that poses as the Adobe Flash Player and runs malicious code in the user's system.","name":"Lastest Adobe Flash Player (malware)","created":"2013-01-14T09:17:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2004fba1-74bf-a072-2a59-6e0ba827b541","last_modified":1480349216871},{"guid":"extension21804@extension21804.com","prefs":[],"schema":1480349193877,"blockID":"i312","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835665","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"Coupon Companion","created":"2013-03-06T14:14:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b2cf1256-dadd-6501-1f4e-25902d408692","last_modified":1480349216827},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i602","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:18:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.8.*","minVersion":"3.15.8","targetApplication":[]}],"id":"b2b4236d-5d4d-82b2-99cd-00ff688badf1","last_modified":1480349216765},{"guid":"nosquint@urandom.ca","prefs":[],"schema":1480349193877,"blockID":"i1232","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1279561","who":"Users on Firefox 47, and higher, using version 2.1.9.1, and earlier, of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"The add-on is breaking the in-built zoom functionality on Firefox 47.","name":"NoSquint","created":"2016-06-10T17:12:55Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.1.9.1-signed.1-signed","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"47"}]}],"id":"30e0a35c-056a-054b-04f3-ade68b83985a","last_modified":1480349216711},{"guid":"{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}","prefs":[],"schema":1480349193877,"blockID":"i364","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867670","who":"All Firefox users who have this add-on installed. Users who want to enable the add-on again can do so in the Add-ons Manager.","why":"This add-on is side-installed with other software, and blocks setting reversions attempted by users who want to recover their settings after they are hijacked by other add-ons.","name":"IB Updater","created":"2013-06-10T16:14:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a59b967c-66ca-7ad9-2dc6-d0ad37ded5fd","last_modified":1480349216652},{"guid":"vpyekkifgv@vpyekkifgv.org","prefs":[],"schema":1480349193877,"blockID":"i352","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=872211","who":"All Firefox users who have this add-on installed.","why":"Uses a deceptive name and injects ads into pages without user consent.","name":"SQLlite Addon (malware)","created":"2013-05-14T13:42:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fd981ab-7ee0-e367-d804-0efe29d63178","last_modified":1480349216614},{"guid":"/^firefox@(albrechto|swiftbrowse|springsmart|storimbo|squirrelweb|betterbrowse|lizardlink|rolimno|browsebeyond|clingclang|weblayers|kasimos|higher-aurum|xaven|bomlabio)\\.(com?|net|org|info|biz)$/","prefs":[],"schema":1480349193877,"blockID":"i549","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937405","who":"All Firefox users who have one or more of these add-ons installed. If you wish to continue using any of these add-ons, they can be enabled in the Add-ons Manager.","why":"A large amount of add-ons developed by Yontoo are known to be silently installed and otherwise violate the Add-on Guidelines.","name":"Yontoo add-ons","created":"2014-01-30T15:08:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a124164-b177-805b-06f7-70a358b37e08","last_modified":1480349216570},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i702","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T10:05:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"1.10","targetApplication":[]}],"id":"60e54f6a-1b10-f889-837f-60a76a98fccc","last_modified":1480349216512},{"guid":"/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i396","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881454","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"PutLockerDownloader and related","created":"2013-06-25T12:48:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e98ba6e3-f2dd-fdee-b106-3e0d2a03cda4","last_modified":1480349216487},{"guid":"my7thfakeid@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i1262","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1295616","who":"Anyone who has this add-on installed.","why":"This add-on is a keylogger that sends the data to a remote server, and goes under the name Real_player.addon.","name":"Remote Keylogger test 0 addon","created":"2016-08-17T10:54:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81b380c0-8092-ea5e-11cd-54c7f563ff5a","last_modified":1480349216460},{"guid":"{f0e59437-6148-4a98-b0a6-60d557ef57f4}","prefs":[],"schema":1480349193877,"blockID":"i304","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845975","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our installation guidelines and is dropped silently into user's profiles.","name":"WhiteSmoke B","created":"2013-02-27T13:10:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0469e643-1a90-f9be-4aad-b347469adcbe","last_modified":1480349216402},{"os":"Darwin,Linux","guid":"firebug@software.joehewitt.com","prefs":[],"schema":1480349193877,"blockID":"i75","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=718831","who":"All Firefox 9 users on Mac OS X or Linux who have Firebug 1.9.0 installed.","why":"Firebug 1.9.0 creates stability problems on Firefox 9, on Mac OS X and Linux. Upgrading to Firefox 10 or later, or upgrading to Firebug 1.9.1 or later fixes this problem.","name":"Firebug","created":"2012-03-21T16:00:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.9.0","minVersion":"1.9.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"9.*","minVersion":"9.0a1"}]}],"id":"a1f9f055-ef34-1412-c39f-35605a70d031","last_modified":1480349216375},{"guid":"xz123@ya456.com","prefs":[],"schema":1480349193877,"blockID":"i486","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-11-15T13:34:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9825a25-a96c-407e-e656-46a7948e5745","last_modified":1480349215808},{"guid":"{C7AE725D-FA5C-4027-BB4C-787EF9F8248A}","prefs":[],"schema":1480349193877,"blockID":"i424","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=860641","who":"Users of Firefox 23 or later who have RelevantKnowledge 1.0.0.2 or lower.","why":"Old versions of this add-on are causing startup crashes in Firefox 23, currently on the Beta channel. RelevantKnowledge users on Firefox 23 and above should update to version 1.0.0.3 of the add-on.","name":"RelevantKnowledge 1.0.0.2 and lower","created":"2013-07-01T10:45:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.0.2","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"23.0a1"}]}],"id":"c888d167-7970-4b3f-240f-2d8e6f14ded4","last_modified":1480349215779},{"guid":"{5C655500-E712-41e7-9349-CE462F844B19}","prefs":[],"schema":1480349193877,"blockID":"i966","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1175425","who":"All users who have this add-on installed.","why":"This add-on is vulnerable to a cross-site scripting attack, putting users at risk when using it in arbitrary websites.","name":"Quick Translator","created":"2015-07-17T13:42:28Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.1-signed","minVersion":"0","targetApplication":[]}],"id":"f34b00a6-c783-7851-a441-0d80fb1d1031","last_modified":1480349215743},{"guid":"superlrcs@svenyor.net","prefs":[],"schema":1480349193877,"blockID":"i545","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949596","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is in violation of the Add-on Guidelines, using multiple add-on IDs and potentially doing other unwanted activities.","name":"SuperLyrics","created":"2014-01-30T11:52:42Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"002cd4fa-4c2b-e28b-9220-4a520f4d9ec6","last_modified":1480349215672},{"guid":"mbrsepone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i479","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937331","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Lightweight Pack (malware)","created":"2013-11-11T15:42:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0549645e-5f50-5089-1f24-6e7d3bfab8e0","last_modified":1480349215645},{"guid":"/^brasilescape.*\\@facebook\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i453","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=918566","who":"All Firefox users who have these add-ons installed.","why":"This is a group of malicious add-ons that use deceitful names like \"Facebook Video Pack\" or \"Mozilla Service Pack\" and hijack Facebook accounts.","name":"Brasil Escape (malware)","created":"2013-09-20T09:54:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8e6b1176-1794-2117-414e-f0821443f27b","last_modified":1480349215591},{"guid":"foxyproxy-basic@eric.h.jung","prefs":[],"schema":1480349193877,"blockID":"i952","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1183890","who":"All users who have this add-on installed on Thunderbird 38 and above.","why":"This add-on is causing consistent startup crashes on Thunderbird 38 and above.","name":"FoxyProxy Basic for Thunderbird","created":"2015-07-15T09:35:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.5.5","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"},{"guid":"{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}","maxVersion":"*","minVersion":"2.35"}]}],"id":"81658491-feda-2ed3-3c6c-8e60c2b73aee","last_modified":1480349215536},{"guid":"mbroctone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i476","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936590","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks the users' Facebook account.","name":"Mozilla Storage Service (malware)","created":"2013-11-08T15:32:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"92198396-8756-8d09-7f18-a68d29894f71","last_modified":1480349215504},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i616","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:24:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.28.*","minVersion":"3.15.28","targetApplication":[]}],"id":"f11b485f-320e-233c-958b-a63377024fad","last_modified":1480349215479},{"guid":"/^({e9df9360-97f8-4690-afe6-996c80790da4}|{687578b9-7132-4a7a-80e4-30ee31099e03}|{46a3135d-3683-48cf-b94c-82655cbc0e8a}|{49c795c2-604a-4d18-aeb1-b3eba27e5ea2}|{7473b6bd-4691-4744-a82b-7854eb3d70b6}|{96f454ea-9d38-474f-b504-56193e00c1a5})$/","prefs":[],"schema":1480349193877,"blockID":"i494","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=776404","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. It also uses multiple add-on IDs for no apparent reason. This violates our Add-on Guidelines.","name":"uTorrent and related","created":"2013-12-02T14:52:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"485210d0-8e69-3436-536f-5d1deeea4167","last_modified":1480349215454},{"guid":"{EB7508CA-C7B2-46E0-8C04-3E94A035BD49}","prefs":[],"schema":1480349193877,"blockID":"i162","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=799266","who":"All Firefox users who have installed any of these add-ons.","why":"This block covers a number of malicious add-ons that deceive users, using names like \"Mozilla Safe Browsing\" and \"Translate This!\", and claiming they are developed by \"Mozilla Corp.\". They hijack searches and redirects users to pages they didn't intend to go to.\r\n\r\nNote: this block won't be active until bug 799266 is fixed.","name":"Mozilla Safe Browsing and others (Medfos malware)","created":"2012-10-11T12:25:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"07566aa3-4ff9-ac4f-9de9-71c77454b4da","last_modified":1480349215428},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i614","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:23:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.26.*","minVersion":"3.15.26","targetApplication":[]}],"id":"ede541f3-1748-7b33-9bd6-80e2f948e14f","last_modified":1480349215399},{"guid":"/^({976cd962-e0ca-4337-aea7-d93fae63a79c}|{525ba996-1ce4-4677-91c5-9fc4ead2d245}|{91659dab-9117-42d1-a09f-13ec28037717}|{c1211069-1163-4ba8-b8b3-32fc724766be})$/","prefs":[],"schema":1480349193877,"blockID":"i522","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:15:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"580aed26-dc3b-eef8-fa66-a0a402447b7b","last_modified":1480349215360},{"guid":"jid0-O6MIff3eO5dIGf5Tcv8RsJDKxrs@jetpack","prefs":[],"schema":1480349193877,"blockID":"i552","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974041","who":"All Firefox users who have this extension installed.","why":"This extension is malware that attempts to make it impossible for a second extension and itself to be disabled, and also forces the new tab page to have a specific URL.","name":"Extension_Protected (malware)","created":"2014-02-19T15:26:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e53063b4-5702-5b66-c860-d368cba4ccb6","last_modified":1480349215327},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i604","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:18:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.11.*","minVersion":"3.15.10","targetApplication":[]}],"id":"b910f779-f36e-70e1-b17a-8afb75988c03","last_modified":1480349215302},{"guid":"brasilescapefive@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i483","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938473","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Facebook Video Pack (malware)","created":"2013-11-14T09:37:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"85ee7840-f262-ad30-eb91-74b3248fd13d","last_modified":1480349215276},{"guid":"brasilescapeeight@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i482","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938476","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Security Pack (malware)","created":"2013-11-14T09:36:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"457a5722-be90-5a9f-5fa0-4c753e9f324c","last_modified":1480349215249},{"guid":"happylyrics@hpyproductions.net","prefs":[],"schema":1480349193877,"blockID":"i370","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881815","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into Firefox without the users' consent, violating our Add-on Guidelines.","name":"Happy Lyrics","created":"2013-06-11T15:42:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"730e616d-94a7-df0c-d31a-98b7875d60c2","last_modified":1480349215225},{"guid":"search-snacks@search-snacks.com","prefs":[],"schema":1480349193877,"blockID":"i872","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082733","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Search Snacks","created":"2015-03-04T14:37:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7567b06f-98fb-9400-8007-5d0357c345d9","last_modified":1480349215198},{"os":"WINNT","guid":"{ABDE892B-13A8-4d1b-88E6-365A6E755758}","prefs":[],"schema":1480349193877,"blockID":"i107","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=764210","who":"All Firefox users on Windows who have the RealPlayer Browser Record extension installed.","why":"The RealPlayer Browser Record extension is causing significant problems on Flash video sites like YouTube. This block automatically disables the add-on, but users can re-enable it from the Add-ons Manager if necessary.\r\n\r\nThis block shouldn't disable any other RealPlayer plugins, so watching RealPlayer content on the web should be unaffected.\r\n\r\nIf you still have problems playing videos on YouTube or elsewhere, please visit our support site for help.","name":"RealPlayer Browser Record Plugin","created":"2012-06-14T13:54:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"15.0.5","minVersion":"0","targetApplication":[]}],"id":"e3b89e55-b35f-8694-6f0e-f856e57a191d","last_modified":1480349215173},{"guid":"/(\\{7aeae561-714b-45f6-ace3-4a8aed6e227b\\})|(\\{01e86e69-a2f8-48a0-b068-83869bdba3d0\\})|(\\{77f5fe49-12e3-4cf5-abb4-d993a0164d9e\\})/","prefs":[],"schema":1480349193877,"blockID":"i436","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=891606","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow the Add-on Guidelines, changing Firefox default settings and not reverting them on uninstall. If you want to continue using this add-on, it can be enabled in the Add-ons Manager.","name":"Visual Bee","created":"2013-08-09T15:04:44Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ad6dc811-ab95-46fa-4bff-42186c149980","last_modified":1480349215147},{"guid":"amo-validator-bypass@example.com","prefs":[],"schema":1480349193877,"blockID":"i1058","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1227605","who":"All users who install this add-on.","why":"This add-on is a proof of concept of a malicious add-on that bypasses the code validator.","name":" AMO Validator Bypass","created":"2015-11-24T09:03:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"86e38e3e-a729-b5a2-20a8-4738b376eea6","last_modified":1480349214743},{"guid":"6lIy@T.edu","prefs":[],"schema":1480349193877,"blockID":"i852","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128269","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"unIsaless","created":"2015-02-09T15:30:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39798bc2-9c75-f172-148b-13f3ca1dde9b","last_modified":1480349214613},{"guid":"{394DCBA4-1F92-4f8e-8EC9-8D2CB90CB69B}","prefs":[],"schema":1480349193877,"blockID":"i100","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=761339","who":"All Firefox users who have Lightshot 2.5.0 installed.","why":"The Lightshot add-on, version 2.5.0, is causing widespread and frequent crashes in Firefox. Lightshot users are strongly recommended to update to version 2.6.0 as soon as possible.","name":"Lightshot","created":"2012-06-05T09:24:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.5.0","minVersion":"2.5.0","targetApplication":[]}],"id":"57829ea2-5a95-1b6e-953c-7c4a7b3b21ac","last_modified":1480349214568},{"guid":"{a7f2cb14-0472-42a1-915a-8adca2280a2c}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i686","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033809","who":"All users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"HomeTab","created":"2014-08-06T16:35:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"33a8f403-b2c8-cadf-e1ba-40b39edeaf18","last_modified":1480349214537},{"guid":"{CA8C84C6-3918-41b1-BE77-049B2BDD887C}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i862","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131230","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Ebay Shopping Assistant by Spigot","created":"2015-02-26T12:51:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9a9d6da2-90a1-5b71-8b24-96492d57dfd1","last_modified":1480349214479},{"guid":"update@firefox.com","prefs":[],"schema":1480349193877,"blockID":"i374","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=781088","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts.","name":"Premium Update (malware)","created":"2013-06-18T13:58:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bb388413-60ea-c9d6-9a3b-c90df950c319","last_modified":1480349214427},{"guid":"sqlmoz@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i350","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=871610","who":"All Firefox users who have this extension installed.","why":"This extension is malware posing as Mozilla software. It hijacks Facebook accounts and spams other Facebook users.","name":"Mozilla Service Pack (malware)","created":"2013-05-13T09:43:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"715082e8-7a30-b27b-51aa-186c38e078f6","last_modified":1480349214360},{"guid":"iobitapps@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i562","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=948695","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is installed silently and changes users settings without reverting them, in violation of the Add-on Guidelines.","name":"IObit Apps Toolbar","created":"2014-02-27T10:00:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be9a54f6-20c1-7dee-3aea-300b336b2ae5","last_modified":1480349214299},{"guid":"{9e09ac65-43c0-4b9d-970f-11e2e9616c55}","prefs":[],"schema":1480349193877,"blockID":"i376","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=857847","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware that hijacks Facebook accounts and posts content on it.","name":"The Social Networks (malware)","created":"2013-06-18T14:16:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"753638b4-65ca-6d71-f1f5-ce32ba2edf3b","last_modified":1480349214246},{"guid":"mozillahmpg@mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i140","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=791867","who":"All Firefox users who have installed this add-on.","why":"This is a malicious add-on that tries to monetize on its users by embedding unauthorized affiliate codes on shopping websites, and sometimes redirecting users to alternate sites that could be malicious in nature.","name":"Google YouTube HD Player (malware)","created":"2012-09-17T16:04:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98150e2e-cb45-1fee-8458-28d3602ec2ec","last_modified":1480349214216},{"guid":"astrovia@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i489","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=942699","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Facebook Security Service (malware)","created":"2013-11-25T12:40:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6f365ff4-e48f-8a06-d19d-55e19fba81f4","last_modified":1480349214157},{"guid":"{bbea93c6-64a3-4a5a-854a-9cc61c8d309e}","prefs":[],"schema":1480349193877,"blockID":"i1126","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that disables various security checks in Firefox.","name":"Tab Extension (malware)","created":"2016-02-29T21:58:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5acb9dcc-59d4-46d1-2a11-1194c4948239","last_modified":1480349214066},{"guid":"ffxtlbr@iminent.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i628","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866943","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using them can enable them in the Add-ons Manager.","why":"These add-ons have been silently installed repeatedly, and change settings without user consent, in violation of the Add-on Guidelines.","name":"Iminent Minibar","created":"2014-06-26T15:47:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4387ad94-8500-d74d-68e3-20564a9aac9e","last_modified":1480349214036},{"guid":"{28387537-e3f9-4ed7-860c-11e69af4a8a0}","prefs":[],"schema":1480349193877,"blockID":"i40","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=665775","who":"Users of MediaBar versions 4.3.1.00 and below in all versions of Firefox.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"MediaBar (2)","created":"2011-07-19T10:19:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.3.1.00","minVersion":"0.1","targetApplication":[]}],"id":"ff95664b-93e4-aa73-ac20-5ffb7c87d8b7","last_modified":1480349214002},{"guid":"{41e5ef7a-171d-4ab5-8351-951c65a29908}","prefs":[],"schema":1480349193877,"blockID":"i784","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"HelpSiteExpert","created":"2014-11-14T14:37:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0c05a0bb-30b4-979e-33a7-9f3955eba17d","last_modified":1480349213962},{"guid":"/^({2d7886a0-85bb-4bf2-b684-ba92b4b21d23}|{2fab2e94-d6f9-42de-8839-3510cef6424b}|{c02397f7-75b0-446e-a8fa-6ef70cfbf12b}|{8b337819-d1e8-48d3-8178-168ae8c99c36}|firefox@neurowise.info|firefox@allgenius.info)$/","prefs":[],"schema":1480349193877,"blockID":"i762","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082599","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"These add-ons are silently installed into users' systems, in violation of the Add-on Guidelines.","name":"SaveSense, neurowise, allgenius","created":"2014-10-17T16:58:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c5439f55-ace5-ad73-1270-017c0ba7b2ce","last_modified":1480349213913},{"guid":"{462be121-2b54-4218-bf00-b9bf8135b23f}","prefs":[],"schema":1480349193877,"blockID":"i226","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812303","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and doesn't do much more than changing the users' settings, without reverting them on removal.","name":"WhiteSmoke","created":"2012-11-29T16:27:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"994c6084-e864-0e4e-ac91-455083ee46c7","last_modified":1480349213879},{"guid":"firefox@browsefox.com","prefs":[],"schema":1480349193877,"blockID":"i546","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936244","who":"All Firefox users who have this add-on installed. If you want to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed, in violation of the Add-on Guidelines.","name":"BrowseFox","created":"2014-01-30T12:26:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"407d8c84-8939-cd28-b284-9b680e529bf6","last_modified":1480349213853},{"guid":"{6926c7f7-6006-42d1-b046-eba1b3010315}","prefs":[],"schema":1480349193877,"blockID":"i382","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844956","who":"All Firefox users who have this add-on installed. Those who wish to continue using it can enable it again in the Add-ons Manager.","why":"This add-on is silently installed, bypassing the Firefox opt-in screen and violating our Add-on Guidelines.","name":"appbario7","created":"2013-06-25T12:05:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2367bd94-2bdd-c615-de89-023ba071a443","last_modified":1480349213825},{"guid":"faststartff@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i866","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131217","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Fast Start","created":"2015-02-26T13:12:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9e730bca-c7d1-da82-64f6-c74de216cb7d","last_modified":1480349213799},{"guid":"05dd836e-2cbd-4204-9ff3-2f8a8665967d@a8876730-fb0c-4057-a2fc-f9c09d438e81.com","prefs":[],"schema":1480349193877,"blockID":"i468","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935135","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be part of a Trojan software package.","name":"Trojan.DownLoader9.50268 (malware)","created":"2013-11-07T14:43:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2fd53d9b-7096-f1fb-fbcb-2b40a6193894","last_modified":1480349213774},{"guid":"jid1-0xtMKhXFEs4jIg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i586","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011286","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware installed without user consent.","name":"ep (malware)","created":"2014-06-03T15:50:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"50ca2179-83ab-1817-163d-39ed2a9fbd28","last_modified":1480349213717},{"guid":"/^({16e193c8-1706-40bf-b6f3-91403a9a22be}|{284fed43-2e13-4afe-8aeb-50827d510e20}|{5e3cc5d8-ed11-4bed-bc47-35b4c4bc1033}|{7429e64a-1fd4-4112-a186-2b5630816b91}|{8c9980d7-0f09-4459-9197-99b3e559660c}|{8f1d9545-0bb9-4583-bb3c-5e1ac1e2920c})$/","prefs":[],"schema":1480349193877,"blockID":"i517","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:54:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e88a28ab-5569-f06d-b0e2-15c51bb2a4b7","last_modified":1480349213344},{"guid":"safebrowse@safebrowse.co","prefs":[],"schema":1480349193877,"blockID":"i782","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1097696","who":"All Firefox users who have this add-on installed.","why":"This add-on loads scripts with malicious code that appears intended to steal usernames, passwords, and other private information.","name":"SafeBrowse","created":"2014-11-12T14:20:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"edd81c91-383b-f041-d8f6-d0b9a90230bd","last_modified":1480349213319},{"guid":"{af95cc15-3b9b-45ae-8d9b-98d08eda3111}","prefs":[],"schema":1480349193877,"blockID":"i492","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945126","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook (malware)","created":"2013-12-02T12:45:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7064e9e2-fba4-7b57-86d7-6f4afbf6f560","last_modified":1480349213294},{"guid":"{84a93d51-b7a9-431e-8ff8-d60e5d7f5df1}","prefs":[],"schema":1480349193877,"blockID":"i744","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080817","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be silently installed into users' systems, and changes settings without consent, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-10-17T15:47:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dbc7ef8b-2c48-5dae-73a0-f87288c669f0","last_modified":1480349213264},{"guid":"{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}","prefs":[],"schema":1480349193877,"blockID":"i918","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:58:16Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"7f2a68f3-aa8a-ae41-1e48-d1f8f63d53c7","last_modified":1480349213231},{"guid":"831778-poidjao88DASfsAnindsd@jetpack","prefs":[],"schema":1480349193877,"blockID":"i972","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190962","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video patch (malware)","created":"2015-08-04T15:18:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39471221-6926-e11b-175a-b28424d49bf6","last_modified":1480349213194},{"guid":"lbmsrvfvxcblvpane@lpaezhjez.org","prefs":[],"schema":1480349193877,"blockID":"i342","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=863385","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. It also appears to install itself both locally and globally, producing a confusing uninstall experience.","name":"RapidFinda","created":"2013-05-06T16:18:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98fb4536-07a4-d03a-f7c5-945acecc8203","last_modified":1480349213128},{"guid":"{babb9931-ad56-444c-b935-38bffe18ad26}","prefs":[],"schema":1480349193877,"blockID":"i499","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946086","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook Credits (malware)","created":"2013-12-04T15:22:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be1d19fa-1662-322a-13e6-5fa5474f33a7","last_modified":1480349213100},{"guid":"{18d5a8fe-5428-485b-968f-b97b05a92b54}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i802","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda Search Addon","created":"2014-12-15T10:52:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bc846147-cdc1-141f-5846-b705c48bd6ed","last_modified":1480349213074},{"guid":"{b6ef1336-69bb-45b6-8cba-e578fc0e4433}","prefs":[],"schema":1480349193877,"blockID":"i780","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Power-SW","created":"2014-11-12T14:00:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3b080157-2900-d071-60fe-52b0aa376cf0","last_modified":1480349213024},{"guid":"info@wxdownloadmanager.com","prefs":[],"schema":1480349193877,"blockID":"i196","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec (malware)","created":"2012-11-05T09:24:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b62597d0-d2cb-d597-7358-5143a1d13658","last_modified":1480349212999},{"os":"WINNT","guid":"{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}","prefs":[],"schema":1480349193877,"blockID":"i111","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=771802","who":"All Firefox users on Windows who have the RealPlayer Browser Record extension installed.","why":"The RealPlayer Browser Record extension is causing significant problems on Flash video sites like YouTube. This block automatically disables the add-on, but users can re-enable it from the Add-ons Manager if necessary.\r\n\r\nThis block shouldn't disable any other RealPlayer plugins, so watching RealPlayer content on the web should be unaffected.\r\n\r\nIf you still have problems playing videos on YouTube or elsewhere, please visit our support site for help.","name":"RealPlayer Browser Record Plugin","created":"2012-07-10T15:28:16Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"15.0.5","minVersion":"0","targetApplication":[]}],"id":"d3f96257-7635-555f-ef48-34d426322992","last_modified":1480349212971},{"guid":"l@AdLJ7uz.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i728","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines","name":"GGoSavee","created":"2014-10-16T16:34:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e6bfa340-7d8a-1627-5cdf-40c0c4982e9d","last_modified":1480349212911},{"guid":"{6b2a75c8-6e2e-4267-b955-43e25b54e575}","prefs":[],"schema":1480349193877,"blockID":"i698","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1052611","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"BrowserShield","created":"2014-08-21T15:46:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"492e4e43-f89f-da58-9c09-d99528ee9ca9","last_modified":1480349212871},{"guid":"/^({65f9f6b7-2dae-46fc-bfaf-f88e4af1beca}|{9ed31f84-c8b3-4926-b950-dff74047ff79}|{0134af61-7a0c-4649-aeca-90d776060cb3}|{02edb56b-9b33-435b-b7df-b2843273a694}|{da51d4f6-3e7e-4ef8-b400-9198e0874606}|{b24577db-155e-4077-bb37-3fdd3c302bb5})$/","prefs":[],"schema":1480349193877,"blockID":"i525","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:11:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"78562d79-9a64-c259-fb63-ce24e29bb141","last_modified":1480349212839},{"guid":"adsremoval@adsremoval.net","prefs":[],"schema":1480349193877,"blockID":"i560","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=962793","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes various user settings, in violation of the Add-on Guidelines.","name":"Ad Removal","created":"2014-02-27T09:57:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4d150ad4-dc22-9790-07a9-36e0a23f857f","last_modified":1480349212798},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i445","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=911966","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that imitates a popular video downloader extension, and attempts to hijack Facebook accounts. The add-on available in the add-ons site is safe to use.","name":"YouTube Enhancer Plus (malware)","created":"2013-09-04T16:53:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.7.0","minVersion":"208.7.0","targetApplication":[]}],"id":"41d75d3f-a57e-d5ad-b95b-22f5fa010b4e","last_modified":1480349212747},{"guid":"suchpony@suchpony.de","prefs":[],"schema":1480349193877,"blockID":"i1264","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have version 1.6.7 or less of this add-on installed.","why":"Old versions of this add-on contained code from YouTube Unblocker, which was originally blocked due to malicious activity. Version 1.6.8 is now okay.","name":"Suchpony (pre 1.6.8)","created":"2016-08-24T10:48:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.6.7","minVersion":"0","targetApplication":[]}],"id":"1bbf00f3-53b5-3777-43c7-0a0b11f9c433","last_modified":1480349212719},{"guid":"{336D0C35-8A85-403a-B9D2-65C292C39087}","prefs":[],"schema":1480349193877,"blockID":"i224","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812292","who":"All Firefox users who have this add-on installed.","why":"This add-on is side-installed with other software, and blocks setting reversions attempted by users who want to recover their settings after they are hijacked by other add-ons.","name":"IB Updater","created":"2012-11-29T16:22:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c87666e6-ec9a-2f1e-ad03-a722d2fa2a25","last_modified":1480349212655},{"guid":"G4Ce4@w.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i718","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and changes settings without consent, in violation of the Add-on Guidelines.","name":"YoutUbeAdBlaocke","created":"2014-10-02T12:21:22Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e1e9322-93e9-4ce1-41f5-46ad4ef1471b","last_modified":1480349212277},{"guid":"extension@Fast_Free_Converter.com","prefs":[],"schema":1480349193877,"blockID":"i533","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949597","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing it.","name":"FastFreeConverter","created":"2013-12-20T15:04:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"726f5645-c0bf-66dc-a97a-d072b46e63e7","last_modified":1480349212247},{"guid":"@stopad","prefs":[],"schema":1480349193877,"blockID":"i1266","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1298780","who":"Users who have version 0.0.4 and earlier of the add-on installed.","why":"Stop Ads sends each visited url to a third party server which is not necessary for the add-on to work or disclosed in a privacy policy or user opt-in. Versions 0.0.4 and earlier are affected.","name":"Stop Ads Addon","created":"2016-08-30T12:24:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.0.4","minVersion":"0","targetApplication":[]}],"id":"3d1893dd-2092-d1f7-03f3-9629b7d7139e","last_modified":1480349212214},{"guid":"703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com","prefs":[],"schema":1480349193877,"blockID":"i519","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:57:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a27d0f9f-7708-3d5f-82e1-e3f29e6098a0","last_modified":1480349212183},{"guid":"imbaty@taringamp3.com","prefs":[],"schema":1480349193877,"blockID":"i662","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that attempts to hide itself by impersonating the Adobe Flash plugin.","name":"Taringa MP3 / Adobe Flash","created":"2014-07-10T15:39:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f43859d4-46b7-c028-4738-d40a73ddad7b","last_modified":1480349212157},{"guid":"{13c9f1f9-2322-4d5c-81df-6d4bf8476ba4}","prefs":[],"schema":1480349193877,"blockID":"i348","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867359","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. It also fails to revert settings changes on removal.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"mywebsearch","created":"2013-05-08T15:55:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"372cf3df-0810-85d8-b5d7-faffff309a11","last_modified":1480349212102},{"guid":"{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}","prefs":[],"schema":1480349193877,"blockID":"i346","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867333","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. Also, it doesn't reset its settings changes on uninstall.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Startnow","created":"2013-05-06T17:06:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1caf911c-ff2f-b0f6-0d32-29ef74be81bb","last_modified":1480349212077},{"guid":"garg_sms@yahoo.in","prefs":[],"schema":1480349193877,"blockID":"i652","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Save My YouTube Day! extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Save My YouTube Day!, version 67.9","created":"2014-07-10T15:17:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"67.9","minVersion":"67.9","targetApplication":[]}],"id":"e50c0189-a7cd-774d-702b-62eade1bf18e","last_modified":1480349212044},{"guid":"9518042e-7ad6-4dac-b377-056e28d00c8f@f1cc0a13-4df1-4d66-938f-088db8838882.com","prefs":[],"schema":1480349193877,"blockID":"i308","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=846455","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed, bypassing our third-party opt-in screen, in violation of our Add-on Guidelines.","name":"Solid Savings","created":"2013-02-28T13:48:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"df25ee07-74d4-ccd9-dbbe-7eb053015144","last_modified":1480349212020},{"guid":"jufa098j-LKooapd9jasJ9jliJsd@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1000","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201163","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Secure Video (malware)","created":"2015-09-07T14:00:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c3a98025-0f4e-3bb4-b475-97329e7b1426","last_modified":1480349211979},{"guid":"{46eddf51-a4f6-4476-8d6c-31c5187b2a2f}","prefs":[],"schema":1480349193877,"blockID":"i750","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963788","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Slick Savings","created":"2014-10-17T16:17:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b4ef650-e1ad-d55f-c420-4f26dbb4139c","last_modified":1480349211953},{"guid":"{DAC3F861-B30D-40dd-9166-F4E75327FAC7}","prefs":[],"schema":1480349193877,"blockID":"i924","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:28:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"be57998b-9e4d-1040-e6bb-ed9de056338d","last_modified":1480349211896},{"guid":"JMLv@njMaHh.org","prefs":[],"schema":1480349193877,"blockID":"i790","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1103516","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"YouttubeAdBlocke","created":"2014-11-24T14:14:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"070d5747-137d-8500-8713-cfc6437558a3","last_modified":1480349211841},{"guid":"istart_ffnt@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i888","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152553","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on appears to be malware, being silently installed and hijacking user settings, in violation of the Add-on Guidelines.","name":"Istart","created":"2015-04-10T16:27:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32fad759-38d9-dad9-2295-e44cc6887040","last_modified":1480349211785},{"guid":"gystqfr@ylgga.com","prefs":[],"schema":1480349193877,"blockID":"i449","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=912742","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It is installed bypassing the Firefox opt-in screen, and manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Define Ext","created":"2013-09-13T16:19:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fe8f509-c530-777b-dccf-d10d58ae78cf","last_modified":1480349211748},{"guid":"e9d197d59f2f45f382b1aa5c14d82@8706aaed9b904554b5cb7984e9.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i844","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128324","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and attempts to change user settings like the home page and default search, in violation of the Add-on Guidelines.","name":"Sense","created":"2015-02-06T15:01:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8f8695c-a356-a1d6-9291-502b377c63c2","last_modified":1480349211713},{"guid":"{184AA5E6-741D-464a-820E-94B3ABC2F3B4}","prefs":[],"schema":1480349193877,"blockID":"i968","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1164243","who":"All users who have this add-on installed.","why":"This is a malicious add-on that poses as a Java extension.","name":"Java String Helper (malware)","created":"2015-08-04T09:41:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fac1d2cb-eed7-fcef-5d5a-43c556371bd7","last_modified":1480349211687},{"guid":"7d51fb17-b199-4d8f-894e-decaff4fc36a@a298838b-7f50-4c7c-9277-df6abbd42a0c.com","prefs":[],"schema":1480349193877,"blockID":"i455","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=919792","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts and posts spam to the users' friends.","name":"Video Console (malware)","created":"2013-09-25T10:28:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dd4d2e17-4ce6-36b0-3035-93e9cc5846d4","last_modified":1480349211660},{"guid":"prositez@prz.com","prefs":[],"schema":1480349193877,"blockID":"i764","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ProfSitez","created":"2014-10-29T16:43:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"684ad4fd-2cbd-ce2a-34cd-bc66b20ac8af","last_modified":1480349211628},{"guid":"/^toolbar[0-9]*@findwide\\.com$/","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i874","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082758","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.\r\n","name":"FindWide Toolbars","created":"2015-03-04T14:54:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a317ad9f-af4d-e086-4afd-cd5eead1ed62","last_modified":1480349211601},{"guid":"{25D77636-38B1-1260-887C-2D4AFA92D6A4}","prefs":[],"schema":1480349193877,"blockID":"i536","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=959279","who":"All Firefox users who have this extension installed.","why":"This is a malicious extension that is installed alongside a trojan. It hijacks searches on selected sites.","name":"Microsoft DirectInput Object (malware)","created":"2014-01-13T10:36:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cd174588-940e-f5b3-12ea-896c957bd4b3","last_modified":1480349211555},{"guid":"fdm_ffext@freedownloadmanager.org","prefs":[],"schema":1480349193877,"blockID":"i216","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=789700","who":"All Firefox users who have installed version 1.5.7.5 of the Free Download Manager extension.","why":"Version 1.5.7.5 of the Free Download Manager extension is causing frequent crashes in recent versions of Firefox. Version 1.5.7.6 corrects this problem, but it is currently not available on addons.mozilla.org. We recommend all users to update to the new version once it becomes available.","name":"Free Download Manager","created":"2012-11-27T12:47:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.5.7.5","minVersion":"1.5.7.5","targetApplication":[]}],"id":"736417a2-6161-9973-991a-aff566314733","last_modified":1480349211163},{"guid":"{badea1ae-72ed-4f6a-8c37-4db9a4ac7bc9}","prefs":[],"schema":1480349193877,"blockID":"i543","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963809","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is apparently malware that is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Address Bar Search","created":"2014-01-28T14:28:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8c1dd68e-7df6-0c37-2f41-107745a7be54","last_modified":1480349211119},{"guid":"addon@gemaoff","prefs":[],"schema":1480349193877,"blockID":"i1230","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"These add-ons are copies of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker (addon@gemaoff)","created":"2016-06-08T16:15:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6bc49e9f-322f-9952-15a6-0a723a61c2d9","last_modified":1480349211044},{"guid":"{d87d56b2-1379-49f4-b081-af2850c79d8e}","prefs":[],"schema":1480349193877,"blockID":"i726","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080835","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Xplorer Lite","created":"2014-10-13T16:01:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7b0895b4-dd4f-1c91-f4e3-31afdbdf3178","last_modified":1480349211007},{"guid":"OKitSpace@OKitSpace.es","prefs":[],"schema":1480349193877,"blockID":"i469","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:35:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6a11aa68-0dae-5524-cc96-a5053a31c466","last_modified":1480349210982},{"guid":"{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}","prefs":[],"schema":1480349193877,"blockID":"i808","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Better Web","created":"2014-12-19T09:36:52Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0413d46b-8205-d9e0-65df-4caa3e6355c4","last_modified":1480349210956},{"guid":"lightningnewtab@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i554","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974041","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed in Firefox and includes a companion extension that also performs malicious actions.","name":"Lightning SpeedDial","created":"2014-02-19T15:28:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"875513e1-e6b1-a383-2ec5-eb4deb87eafc","last_modified":1480349210931},{"guid":"/^ext@bettersurfplus/","prefs":[],"schema":1480349193877,"blockID":"i506","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-12-10T15:10:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b4da06d2-a0fd-09b6-aadb-7e3b29c3be3a","last_modified":1480349210905},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i706","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T14:50:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.6.160","minVersion":"1.6.160","targetApplication":[]}],"id":"bb2b2114-f8e7-511d-04dc-abc8366712cc","last_modified":1480349210859},{"guid":"CortonExt@ext.com","prefs":[],"schema":1480349193877,"blockID":"i336","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=864551","who":"All Firefox users who have this add-on installed.","why":"This add-on is reported to be installed without user consent, with a non-descriptive name, and ties a number of browser features to Amazon URLs, probably monetizing on affiliate codes.","name":"CortonExt","created":"2013-04-22T16:10:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a5bdd05d-eb4c-ce34-9909-a677b4322384","last_modified":1480349210805},{"guid":"1chtw@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i430","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=901770","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that uses a deceptive name and hijacks social networks.","name":" Mozilla Service Pack (malware)","created":"2013-08-05T16:42:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bf1e31c7-ba50-1075-29ae-47368ac1d6de","last_modified":1480349210773},{"guid":"lrcsTube@hansanddeta.com","prefs":[],"schema":1480349193877,"blockID":"i344","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866944","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"LyricsTube","created":"2013-05-06T16:44:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"424b9f39-d028-b1fb-d011-d8ffbbd20fe9","last_modified":1480349210718},{"guid":"{341f4dac-1966-47ff-aacf-0ce175f1498a}","prefs":[],"schema":1480349193877,"blockID":"i356","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=868129","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"MyFreeGames","created":"2013-05-23T14:45:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"560e08b1-3471-ad34-8ca9-463f5ca5328c","last_modified":1480349210665},{"guid":"/^({d6e79525-4524-4707-9b97-1d70df8e7e59}|{ddb4644d-1a37-4e6d-8b6e-8e35e2a8ea6c}|{e55007f4-80c5-418e-ac33-10c4d60db01e}|{e77d8ca6-3a60-4ae9-8461-53b22fa3125b}|{e89a62b7-248e-492f-9715-43bf8c507a2f}|{5ce3e0cb-aa83-45cb-a7da-a2684f05b8f3})$/","prefs":[],"schema":1480349193877,"blockID":"i518","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:56:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"145b0f22-501e-39eb-371e-ec8342a5add9","last_modified":1480349210606},{"guid":"{72b98dbc-939a-4e0e-b5a9-9fdbf75963ef}","prefs":[],"schema":1480349193877,"blockID":"i772","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"SitezExpert","created":"2014-10-31T16:15:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"386cb2c9-e674-ce2e-345f-d30a785f90c5","last_modified":1480349210536},{"guid":"hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack","prefs":[],"schema":1480349193877,"blockID":"i970","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190963","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video fix (malware)","created":"2015-08-04T15:15:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3ca577d8-3685-4ba9-363b-5b2d8d8dd608","last_modified":1480349210477},{"guid":"{7e8a1050-cf67-4575-92df-dcc60e7d952d}","prefs":[],"schema":1480349193877,"blockID":"i478","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935796","who":"All Firefox users who have this add-on installed.","why":"This add-on violates the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"SweetPacks","created":"2013-11-08T15:42:28Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1519eb45-fcaa-b531-490d-fe366490ed45","last_modified":1480349210416},{"guid":"/^({66b103a7-d772-4fcd-ace4-16f79a9056e0}|{6926c7f7-6006-42d1-b046-eba1b3010315}|{72cabc40-64b2-46ed-8648-26d831761150}|{73ee2cf2-7b76-4c49-b659-c3d8cf30825d}|{ca6446a5-73d5-4c35-8aa1-c71dc1024a18}|{5373a31d-9410-45e2-b299-4f61428f0be4})$/","prefs":[],"schema":1480349193877,"blockID":"i521","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:14:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"983cb7fe-e0b4-6a2e-f174-d2670876b2cd","last_modified":1480349210351},{"guid":"{dd6b651f-dfb9-4142-b0bd-09912ad22674}","prefs":[],"schema":1480349193877,"blockID":"i400","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"975d2126-f727-f5b9-ca01-b83345b80c56","last_modified":1480349210301},{"guid":"25p@9eAkaLq.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i730","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines\r\n","name":"YYOutoubeAdBlocke","created":"2014-10-16T16:35:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5a0c5818-693f-43ae-f85a-c6928d9c2cc4","last_modified":1480349210275},{"os":"Darwin","guid":"thunder@xunlei.com","prefs":[],"schema":1480349193877,"blockID":"i568","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=988490","who":"All Firefox users who have versions 2.0.6 or lower of the Thunder add-on installed on Mac OS.","why":"Versions 2.0.6 and lower of the Thunder add-on are causing startup crashes on Mac OS.","name":"Thunder, 2.0.6 and lower","created":"2014-03-28T15:48:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.6","minVersion":"0","targetApplication":[]}],"id":"cee484f6-2d5d-f708-88be-cd12d825a79a","last_modified":1480349210242},{"guid":"tmbepff@trendmicro.com","prefs":[],"schema":1480349193877,"blockID":"i1222","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1275245","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"Add-on is causing a high-frequency crash in Firefox","name":"Trend Micro BEP 9.1.0.1035 and lower","created":"2016-05-24T12:10:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.1.0.1035","minVersion":"0","targetApplication":[]}],"id":"8045c799-486a-927c-b972-b9da1c2dab2f","last_modified":1480349209818},{"guid":"pricepeep@getpricepeep.com","prefs":[],"schema":1480349193877,"blockID":"i220","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=811433","who":"All Firefox users who have Pricepeed below 2.1.0.20 installed.","why":"Versions older than 2.1.0.20 of the PricePeep add-on were silently side-installed with other software, injecting advertisements in Firefox. Versions 2.1.0.20 and above don't have the install problems are not blocked.","name":"PricePeep","created":"2012-11-29T16:18:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.1.0.19.99","minVersion":"0","targetApplication":[]}],"id":"227b9a8d-c18d-239c-135e-d79e614fe392","last_modified":1480349209794},{"guid":"ytd@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i360","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845969","who":"All Firefox users who have this add-on installed. Users who want to enable the add-on again can do so in the Add-ons Manager tab.","why":"The installer that includes this add-on performs Firefox settings changes separately from the add-on install, making it very difficult to opt-out to these changes.","name":"YouTube Downloader","created":"2013-06-06T12:29:13Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"63669524-93fe-4823-95ba-37cf6cbd4914","last_modified":1480349209770},{"guid":"hoverst@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i498","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946029","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Adobe Flash Player (malware)","created":"2013-12-04T15:17:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2b25ba3e-45db-0e6c-965a-3acda1a44117","last_modified":1480349209745},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i606","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:20:07Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.13.*","minVersion":"3.15.13","targetApplication":[]}],"id":"c3d88e22-386a-da3b-8aba-3cb526e08053","last_modified":1480349209713},{"guid":"advance@windowsclient.com","prefs":[],"schema":1480349193877,"blockID":"i508","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950773","who":"All Firefox users who have this add-on installed.","why":"This is not the Microsoft .NET Framework Assistant created and distributed by Microsoft. It is a malicious extension that is distributed under the same name to trick users into installing it, and turns users into a botnet that conducts SQL injection attacks on visited websites.","name":"Microsoft .NET Framework Assistant (malware)","created":"2013-12-16T10:15:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e5d30a74-732e-c3fa-f13b-097ee28d4b27","last_modified":1480349209674},{"guid":"{5eeb83d0-96ea-4249-942c-beead6847053}","prefs":[],"schema":1480349193877,"blockID":"i756","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080846","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"SmarterPower","created":"2014-10-17T16:30:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e101dbc0-190c-f6d8-e168-0c1380581cc9","last_modified":1480349209625},{"guid":"/^({7e8a1050-cf67-4575-92df-dcc60e7d952d}|{b3420a9c-a397-4409-b90d-bcf22da1a08a}|{eca6641f-2176-42ba-bdbe-f3e327f8e0af}|{707dca12-3f99-4d94-afea-06dcc0ae0108}|{aea20431-87fc-40be-bc5b-18066fe2819c}|{30ee6676-1ba6-455a-a7e8-298fa863a546})$/","prefs":[],"schema":1480349193877,"blockID":"i523","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947481","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"SweetPacks","created":"2013-12-20T13:42:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a3a6bc8e-46a1-b3d5-1b20-58b90ba099c3","last_modified":1480349209559},{"guid":"{e0352044-1439-48ba-99b6-b05ed1a4d2de}","prefs":[],"schema":1480349193877,"blockID":"i710","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Site Counselor","created":"2014-09-30T15:28:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b8fedf07-dcaf-f0e3-b42b-32db75c4c304","last_modified":1480349209491},{"guid":"{bee6eb20-01e0-ebd1-da83-080329fb9a3a}","prefs":[],"schema":1480349193877,"blockID":"i642","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Flash and Video Download extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Flash and Video Download, between 40.10.1 and 44.10.1","created":"2014-07-10T15:02:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"44.10.1","minVersion":"40.10.1","targetApplication":[]}],"id":"16db0c85-02ec-4f7c-24a3-a504fbce902d","last_modified":1480349209443},{"guid":"addlyrics@addlyrics.net","prefs":[],"schema":1480349193877,"blockID":"i426","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=891605","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Add Lyrics","created":"2013-07-09T15:25:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81678e9e-ebf0-47d6-e409-085c25e67c7e","last_modified":1480349209383},{"guid":"{7b1bf0b6-a1b9-42b0-b75d-252036438bdc}","prefs":[],"schema":1480349193877,"blockID":"i638","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036137","who":"All Firefox users who have this version of the add-on installed.","why":"Versions 27.8 and 27.9 of the YouTube High Definition extension weren't developed by the original developer, and are likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube High Definition 27.8 and 27.9","created":"2014-07-08T16:07:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"27.9","minVersion":"27.8","targetApplication":[]}],"id":"ffdc8ba0-d548-dc5b-d2fd-79a20837124b","last_modified":1480349209260},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i610","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:21:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.22.*","minVersion":"3.15.22","targetApplication":[]}],"id":"935dfec3-d017-5660-db5b-94ae7cea6e5f","last_modified":1480349209128},{"guid":"info@allpremiumplay.info","prefs":[],"schema":1480349193877,"blockID":"i163","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec-C (malware)","created":"2012-10-29T16:40:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6afbf9b8-ae3a-6a48-0f6c-7a3e065ec043","last_modified":1480349209076},{"guid":"now.msn.com@services.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i490","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=926378","who":"All Firefox users who have this add-on installed.","why":"As part of their ongoing work to fine-tune their editorial mix, msnNOW has decided that msnNOW will stop publishing on Dec. 3, 2013. Rather than having a single home for trending content, they will continue integrating that material throughout all MSN channels. A big thank you to everyone who followed msnNOW stories using the Firefox sidebar","name":"MSNNow (discontinued social provider)","created":"2013-11-27T08:06:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"de7d699d-016d-d973-5e39-52568de6ffde","last_modified":1480349209021},{"guid":"fftoolbar2014@etech.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i858","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131078","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and changes users' settings, in violation of the Add-on Guidelines.","name":"FF Toolbar","created":"2015-02-11T15:32:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6877bf40-9e45-7017-4dac-14d09e7f0ef6","last_modified":1480349208988},{"guid":"mbrnovone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i477","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936249","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Security Service (malware)","created":"2013-11-08T15:35:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"758c2503-766d-a2f5-4c58-7cea93acfe05","last_modified":1480349208962},{"guid":"{739df940-c5ee-4bab-9d7e-270894ae687a}","prefs":[],"schema":1480349193877,"blockID":"i530","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949558","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"WhiteSmoke New","created":"2013-12-20T14:49:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8097aa6-3009-6dfc-59df-353ba6b1142b","last_modified":1480349208933},{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","prefs":[],"schema":1480349193877,"blockID":"i115","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=779014","who":"All Firefox users who have this add-on installed.","why":"This extension is malware that is installed under false pretenses, and it conducts attacks against certain video websites.","name":"Adobe Flash Player (malware)","created":"2012-08-01T13:53:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aef9312d-5f2e-a44d-464d-6113394148e3","last_modified":1480349208904},{"guid":"g99hiaoekjoasiijdkoleabsy278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1022","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208708","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"WatchIt (malware)","created":"2015-09-28T15:23:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"25e057ea-f500-67df-d078-ec3f37f99036","last_modified":1480349208877},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i636","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033120","who":"All Firefox users who have this version of the add-on installed.","why":"Version 199.7.0 of the YoutubeEnhancer extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YoutubeEnhancer - Firefox","created":"2014-07-08T15:58:12Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"199.7.0","minVersion":"199.7.0","targetApplication":[]}],"id":"204a074b-da87-2784-f15b-43a9ea9a6b36","last_modified":1480349208851},{"guid":"extacylife@a.com","prefs":[],"schema":1480349193877,"blockID":"i505","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947741","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-09T15:08:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5acadb8d-d3be-e0e0-4656-9107f9de0ea9","last_modified":1480349208823},{"guid":"{746505DC-0E21-4667-97F8-72EA6BCF5EEF}","prefs":[],"schema":1480349193877,"blockID":"i842","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128325","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Shopper-Pro","created":"2015-02-06T14:45:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f19c5fb-1c78-cbd6-8a03-1678efb54cbc","last_modified":1480349208766},{"guid":"{51c77233-c0ad-4220-8388-47c11c18b355}","prefs":[],"schema":1480349193877,"blockID":"i580","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1004132","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed into Firefox, in violation of the Add-on Guidelines.","name":"Browser Utility","created":"2014-04-30T13:55:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.1.9999999","minVersion":"0","targetApplication":[]}],"id":"daa2c60a-5009-2c65-a432-161d50bef481","last_modified":1480349208691},{"guid":"{a2bfe612-4cf5-48ea-907c-f3fb25bc9d6b}","prefs":[],"schema":1480349193877,"blockID":"i712","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Xplorer","created":"2014-09-30T15:28:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"13450534-93d7-f2a2-7f0a-e4e3948c4dc1","last_modified":1480349208027},{"guid":"ScorpionSaver@jetpack","prefs":[],"schema":1480349193877,"blockID":"i539","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963826","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is being silently installed, in violation of the Add-on Guidelines","name":"ScorpionSaver","created":"2014-01-28T14:00:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3499c968-6e8b-37f1-5f6e-2384807c2a6d","last_modified":1480349207972},{"guid":"unblocker20@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1212","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 2.0","created":"2016-05-05T18:13:29Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0.0","minVersion":"0","targetApplication":[]}],"id":"57785030-909f-e985-2a82-8bd057781227","last_modified":1480349207912},{"guid":"{D19CA586-DD6C-4a0a-96F8-14644F340D60}","prefs":[],"schema":1480349193877,"blockID":"i42","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=690184","who":"Users of McAfee ScriptScan versions 14.4.0 and below for all versions of Firefox and SeaMonkey.","why":"This add-on causes a high volume of crashes.","name":"McAfee ScriptScan","created":"2011-10-03T09:38:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"14.4.0","minVersion":"0.1","targetApplication":[]}],"id":"1d35ac9d-49df-23cf-51f5-f3c228ad0dc9","last_modified":1480349207877},{"guid":"gjhrjenrengoe@jfdnkwelfwkm.com","prefs":[],"schema":1480349193877,"blockID":"i1042","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1212174","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Avant Player (malware)","created":"2015-10-07T13:12:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d6453893-becc-7617-2050-0db284e0e0db","last_modified":1480349207840},{"guid":"/^(@9338379C-DD5C-4A45-9A36-9733DC806FAE|9338379C-DD5C-4A45-9A36-9733DC806FAE|@EBC7B466-8A28-4061-81B5-10ACC05FFE53|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4222|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4|@b2d6a97c0-4b18-40ed-bce7-3b7d3309e3c4222)$/","prefs":[],"schema":1480349193877,"blockID":"i1079","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1240597","who":"All Firefox users who have these add-ons installed.","why":"These add-ons are malicious, manipulating registry and search settings for users.","name":"Default SearchProtected (malware)","created":"2016-01-18T12:32:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ddc5237e-42e4-1bf1-54d3-a5e5799dd828","last_modified":1480349207815},{"guid":"{33e0daa6-3af3-d8b5-6752-10e949c61516}","prefs":[],"schema":1480349193877,"blockID":"i282","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835683","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on violates our add-on guidelines, bypassing the third party opt-in screen.","name":"Complitly","created":"2013-02-15T12:19:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.1.999","minVersion":"0","targetApplication":[]}],"id":"1f94bc8d-9d5f-c8f5-45c0-ad1f6e147c71","last_modified":1480349207789},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i608","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:20:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.20.*","minVersion":"3.15.18","targetApplication":[]}],"id":"e7d50ff2-5948-d571-6711-37908ccb863f","last_modified":1480349207761},{"guid":"chiang@programmer.net","prefs":[],"schema":1480349193877,"blockID":"i340","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867156","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that logs keyboard input and sends it to a remote server.","name":"Cache Manager (malware)","created":"2013-04-30T07:44:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d50d0434-78e4-faa7-ce2a-9b0a8bb5120e","last_modified":1480349207736},{"guid":"{63eb5ed4-e1b3-47ec-a253-f8462f205350}","prefs":[],"schema":1480349193877,"blockID":"i786","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"FF-Plugin","created":"2014-11-18T12:33:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ca4558a2-8ce4-3ca0-3d29-63019f680c8c","last_modified":1480349207705},{"guid":"jid1-4vUehhSALFNqCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i634","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033002","who":"All Firefox users who have this version of the add-on installed.","why":"Version 99.7 of the YouTube Plus Plus extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Plus Plus 99.7","created":"2014-07-04T14:13:57Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"99.7","minVersion":"99.7","targetApplication":[]}],"id":"a6d017cb-e33f-2239-4e42-ab4e7cfb19fe","last_modified":1480349207680},{"guid":"{aab02ab1-33cf-4dfa-8a9f-f4e60e976d27}","prefs":[],"schema":1480349193877,"blockID":"i820","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent, in violation of the Add-on Guidelines.","name":"Incredible Web","created":"2015-01-13T09:27:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"847ecc6e-1bc1-f7ff-e1d5-a76e6b8447d2","last_modified":1480349207654},{"guid":"torntv@torntv.com","prefs":[],"schema":1480349193877,"blockID":"i320","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845610","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"TornTV","created":"2013-03-20T16:35:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cdd492b8-8101-74a9-5760-52ff709fd445","last_modified":1480349207608},{"guid":"crossriderapp12555@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i674","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=877836","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"The add-on is silently installed, in violation of our Add-on Guidelines.","name":"JollyWallet","created":"2014-07-22T16:26:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d4467e20-0f71-f0e0-8cd6-40c82b6c7379","last_modified":1480349207561},{"guid":"pluggets@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i435","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=903544","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks users' Facebook accounts and posts spam on their behalf. ","name":"Facebook Pluggets Plugin (malware)","created":"2013-08-09T13:12:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a63fd92-9290-02fb-a2e8-bc1b4424201a","last_modified":1480349207535},{"guid":"344141-fasf9jas08hasoiesj9ia8ws@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1038","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211169","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video Plugin (malware)","created":"2015-10-05T16:42:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7986b7b-9b5a-d372-8147-8b4bd6f5a29b","last_modified":1480349207485},{"guid":"meOYKQEbBBjH5Ml91z0p9Aosgus8P55bjTa4KPfl@jetpack","prefs":[],"schema":1480349193877,"blockID":"i998","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201164","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Smooth Player (malware)","created":"2015-09-07T13:54:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"30c3e511-9e8d-15ee-0867-d61047e56515","last_modified":1480349207370},{"guid":"{8dc5c42e-9204-2a64-8b97-fa94ff8a241f}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i770","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088726","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astrmenda Search","created":"2014-10-30T14:52:52Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8a9c7702-0349-70d6-e64e-3a666ab084c6","last_modified":1480349207320},{"guid":"savingsslider@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i752","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963788","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Slick Savings","created":"2014-10-17T16:18:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b1faf30-5725-7847-d993-b5cdaabc9829","last_modified":1480349207290},{"guid":"youtubeunblocker__web@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1129","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that is being exploited through this website (unblocker.yt) to change security settings in Firefox and install malicious add-ons.","name":"YouTube Unblocker","created":"2016-03-01T21:20:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aa246b36-0a80-81e3-2129-4847e872d5fe","last_modified":1480349207262},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i612","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:23:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.24.*","minVersion":"3.15.24","targetApplication":[]}],"id":"e0ff9df4-60e4-dbd0-8018-57f395e6610a","last_modified":1480349206818},{"guid":"{1e4ea5fc-09e5-4f45-a43b-c048304899fc}","prefs":[],"schema":1480349193877,"blockID":"i812","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Great Finder","created":"2015-01-06T13:22:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ea40b9f-2423-a2fd-a5e9-4ec1df2715f4","last_modified":1480349206784},{"guid":"psid-vhvxQHMZBOzUZA@jetpack","prefs":[],"schema":1480349193877,"blockID":"i70","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=730059","who":"All Firefox users who have installed this add-on.","why":"Add-on spams Facebook accounts and blocks Facebook warnings.","name":"PublishSync (malware)","created":"2012-02-23T13:44:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f1528b02-7cef-0e80-f747-8bbf1f0f2f06","last_modified":1480349206758},{"guid":"{B18B1E5C-4D81-11E1-9C00-AFEB4824019B}","prefs":[],"schema":1480349193877,"blockID":"i447","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=788838","who":"All Firefox users who have this add-on installed. The add-on can be enabled again in the Add-ons Manager.","why":"This add-on is installed silently, in violation of our Add-on Guidelines.","name":"My Smart Tabs","created":"2013-09-06T16:00:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"40332fae-0444-a141-ade9-8d9e50370f56","last_modified":1480349206733},{"guid":"crossriderapp8812@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i314","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835665","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"Coupon Companion","created":"2013-03-06T14:14:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"06c07e28-0a34-e5ee-e724-491a2f6ce586","last_modified":1480349206708},{"guid":"/^(ffxtlbr@mixidj\\.com|{c0c2693d-2ee8-47b4-9df7-b67a0ee31988}|{67097627-fd8e-4f6b-af4b-ecb65e50112e}|{f6f0f973-a4a3-48cf-9a7a-b7a69c30d71a}|{a3d0e35f-f1da-4ccb-ae77-e9d27777e68d}|{1122b43d-30ee-403f-9bfa-3cc99b0caddd})$/","prefs":[],"schema":1480349193877,"blockID":"i540","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed.","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:07:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4c03ddda-bb3f-f097-0a7b-b7b77b050584","last_modified":1480349206678},{"guid":"hansin@topvest.id","prefs":[],"schema":1480349193877,"blockID":"i836","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1130406","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Inside News (malware)","created":"2015-02-06T14:17:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0945a657-f28d-a02c-01b2-5115b3f90d7a","last_modified":1480349206628},{"guid":"lfind@nijadsoft.net","prefs":[],"schema":1480349193877,"blockID":"i358","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=874131","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Lyrics Finder","created":"2013-05-24T14:09:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2307f11c-6216-0dbf-a464-b2921055ce2b","last_modified":1480349206603},{"guid":"plugin@getwebcake.com","prefs":[],"schema":1480349193877,"blockID":"i484","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938264","who":"All Firefox users who have this add-on installed.","why":"This add-on violates the Add-on Guidelines and is broadly considered to be malware. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"WebCake","created":"2013-11-14T09:55:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2865addd-da1c-20c4-742f-6a2270da2e78","last_modified":1480349206578},{"guid":"{c0c2693d-2ee8-47b4-9df7-b67a0ee31988}","prefs":[],"schema":1480349193877,"blockID":"i354","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=837838","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Mixi DJ","created":"2013-05-23T14:31:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"03a745c3-0ee7-e262-ba31-62d4f78ddb62","last_modified":1480349206525},{"guid":"/^({7316e43a-3ebd-4bb4-95c1-9caf6756c97f}|{0cc09160-108c-4759-bab1-5c12c216e005}|{ef03e721-f564-4333-a331-d4062cee6f2b}|{465fcfbb-47a4-4866-a5d5-d12f9a77da00}|{7557724b-30a9-42a4-98eb-77fcb0fd1be3}|{b7c7d4b0-7a84-4b73-a7ef-48ef59a52c3b})$/","prefs":[],"schema":1480349193877,"blockID":"i520","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:11:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3901c48-9c06-fecb-87d3-efffd9940c22","last_modified":1480349206491},{"guid":"{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}","prefs":[],"schema":1480349193877,"blockID":"i538","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=964081","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Show Mask ON (malware)","created":"2014-01-27T10:13:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aad90253-8921-b5df-3658-45a70d75f3d7","last_modified":1480349206465},{"guid":"{8E9E3331-D360-4f87-8803-52DE43566502}","prefs":[],"schema":1480349193877,"blockID":"i461","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=906071","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This is a companion add-on for the SweetPacks Toolbar which is blocked due to guideline violations.","name":"Updater By SweetPacks","created":"2013-10-17T16:10:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ae8cca6e-4258-545f-9a69-3d908264a701","last_modified":1480349206437},{"guid":"info@bflix.info","prefs":[],"schema":1480349193877,"blockID":"i172","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806802","who":"All Firefox users who have this add-on installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Bflix (malware)","created":"2012-10-30T13:39:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7a9062f4-218d-51d2-9b8c-b282e6eada4f","last_modified":1480349206384},{"guid":"{dff137ae-1ffd-11e3-8277-b8ac6f996f26}","prefs":[],"schema":1480349193877,"blockID":"i450","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=917861","who":"All Firefox users who have this add-on installed.","why":"This is add-on is malware that silently redirects popular search queries to a third party.","name":"Addons Engine (malware)","created":"2013-09-18T16:19:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8e583fe4-1c09-9bea-2473-faecf3260685","last_modified":1480349206312},{"guid":"12x3q@3244516.com","prefs":[],"schema":1480349193877,"blockID":"i493","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-12-02T12:49:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"af2a9e74-3753-9ff1-d899-5d1e79ed3dce","last_modified":1480349206286},{"guid":"{20AD702C-661E-4534-8CE9-BA4EC9AD6ECC}","prefs":[],"schema":1480349193877,"blockID":"i626","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1027886","who":"All Firefox users who have this add-on installed.","why":"This add-on is probably silently installed, and is causing significant stability issues for users, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-06-19T15:16:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b9ccabe-8f9a-e3d1-a689-1aefba1f33b6","last_modified":1480349206261},{"guid":"{c5e48979-bd7f-4cf7-9b73-2482a67a4f37}","prefs":[],"schema":1480349193877,"blockID":"i736","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080842","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"ClearThink","created":"2014-10-17T15:22:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6e8b3e4f-2f59-cde3-e6d2-5bc6e216c506","last_modified":1480349206231},{"guid":"{41339ee8-61ed-489d-b049-01e41fd5d7e0}","prefs":[],"schema":1480349193877,"blockID":"i810","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"FireWeb","created":"2014-12-23T10:32:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a35f2ca6-aec4-c01d-170e-650258ebcd2c","last_modified":1480349206165},{"guid":"jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack","prefs":[],"schema":1480349193877,"blockID":"i640","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036640","who":"All Firefox users who have this add-on installed.","why":"This add-on attempts to gather private user data and send it to a remote location. It doesn't appear to be very effective at it, but its malicious nature is undeniable.","name":"Bitcoin Mining Software","created":"2014-07-09T14:35:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fe3c35e-1a6f-a89a-fa96-81bda3b71db1","last_modified":1480349206133},{"guid":"{845cab51-d8d2-472f-8bd9-2b44642d97c2}","prefs":[],"schema":1480349193877,"blockID":"i460","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=927456","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and handles users' settings, violating some of the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Vafmusic9","created":"2013-10-17T15:50:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8538ccb4-3b71-9858-3f6d-c0fff7af58b0","last_modified":1480349205746},{"guid":"SpecialSavings@SpecialSavings.com","prefs":[],"schema":1480349193877,"blockID":"i676","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881511","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This is add-on is generally considered to be unwanted and is probably silently installed, in violation of the Add-on Guidelines.","name":"SpecialSavings","created":"2014-07-22T16:31:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5e921810-fc3a-0729-6749-47e38ad10a22","last_modified":1480349205688},{"guid":"afurladvisor@anchorfree.com","prefs":[],"schema":1480349193877,"blockID":"i434","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844945","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield Helper","created":"2013-08-09T11:26:11Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"083585eb-d7e7-e228-5fbf-bf35c52044e4","last_modified":1480349205645},{"guid":"addonhack@mozilla.kewis.ch","prefs":[],"schema":1480349193877,"blockID":"i994","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1200848","who":"All users who have this add-on installed.","why":"This add-on is a proof of concept of malicious behavior in an add-on. In itself it doesn't cause any harm, but it still needs to be blocked for security reasons.","name":"Addon Hack","created":"2015-09-01T15:32:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81f75571-ca2a-0e50-a925-daf2037ce63c","last_modified":1480349205584},{"guid":"info@thebflix.com","prefs":[],"schema":1480349193877,"blockID":"i174","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806802","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Bflix (malware)","created":"2012-10-30T13:40:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"811a61d4-9435-133e-6262-fb72486c36b0","last_modified":1480349205526},{"guid":"{EEE6C361-6118-11DC-9C72-001320C79847}","prefs":[],"schema":1480349193877,"blockID":"i392","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881447","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. This violates our Add-on Guidelines.","name":"SweetPacks Toolbar","created":"2013-06-25T12:38:45Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c1dc6607-4c0a-4031-9f14-70ef1ae1edcb","last_modified":1480349205455},{"guid":"/^(4cb61367-efbf-4aa1-8e3a-7f776c9d5763@cdece6e9-b2ef-40a9-b178-291da9870c59\\.com|0efc9c38-1ec7-49ed-8915-53a48b6b7600@e7f17679-2a42-4659-83c5-7ba961fdf75a\\.com|6be3335b-ef79-4b0b-a0ba-b87afbc6f4ad@6bbb4d2e-e33e-4fa5-9b37-934f4fb50182\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i531","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949672","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"Feven","created":"2013-12-20T15:01:22Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"46aa79a9-d329-f713-d4f2-07d31fe7071e","last_modified":1480349205287},{"guid":"afext@anchorfree.com","prefs":[],"schema":1480349193877,"blockID":"i466","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=933988","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't respect user choice, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield Extension","created":"2013-11-07T13:32:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8176f879-bd73-5468-e908-2d7cfc115ac2","last_modified":1480349205108},{"guid":"{FCE04E1F-9378-4f39-96F6-5689A9159E45}","prefs":[],"schema":1480349193877,"blockID":"i920","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:26:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"eb191ff0-20f4-6e04-4344-d880af4faf51","last_modified":1480349204978},{"guid":"{9CE11043-9A15-4207-A565-0C94C42D590D}","prefs":[],"schema":1480349193877,"blockID":"i503","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947384","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that uses a deceptive name to stay in users' systems.","name":"XUL Cache (malware)","created":"2013-12-06T11:58:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dcdae267-8d3a-5671-dff2-f960febbbb20","last_modified":1480349204951},{"guid":"/^[a-z0-9]+@foxysecure[a-z0-9]*\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i766","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088615","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Fox Sec 7","created":"2014-10-30T14:22:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"503fbd7c-04cd-65f3-9d0e-3ecf427b4a8f","last_modified":1480349204925},{"guid":"/^(jid1-W4CLFIRExukJIFW@jetpack|jid1-W4CLFIRExukJIFW@jetpack_1|jid1-W3CLwrP[a-z]+@jetpack)$/","prefs":[],"schema":1480349193877,"blockID":"i1078","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1240561","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that tries to pass itself for the Adobe Flash Player and hides itself in the Add-ons Manager.","name":"Adobe Flash Player (malware)","created":"2016-01-18T10:31:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b026fe67-ec77-a240-2fa1-e78f581a6fe4","last_modified":1480349204899},{"guid":"{0153E448-190B-4987-BDE1-F256CADA672F}","prefs":[],"schema":1480349193877,"blockID":"i914","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:56:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"2bfe0d89-e458-9d0e-f944-ddeaf8c4db6c","last_modified":1480349204871},{"guid":"{77beece6-3997-403a-92fa-0055bfcf88e5}","prefs":[],"schema":1480349193877,"blockID":"i452","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=916966","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, manipulating settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Entrusted11","created":"2013-09-18T16:34:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d348f91f-caeb-a803-dfd9-fd5d285aa0fa","last_modified":1480349204844},{"guid":"dealcabby@jetpack","prefs":[],"schema":1480349193877,"blockID":"i222","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=811435","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed with other software, injecting advertisements in Firefox.","name":"DealCabby","created":"2012-11-29T16:20:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6585f0bd-4f66-71e8-c565-d9762c5c084a","last_modified":1480349204818},{"guid":"{3c9a72a0-b849-40f3-8c84-219109c27554}","prefs":[],"schema":1480349193877,"blockID":"i510","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=951301","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-17T14:27:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7cfa3d0b-0ab2-5e3a-8143-1031c180e32f","last_modified":1480349204778},{"guid":"{4ED1F68A-5463-4931-9384-8FFF5ED91D92}","prefs":[],"schema":1480349193877,"blockID":"i1245","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1286368","who":"All users who have McAfee SiteAdvisor lower than 4.0. \r\n\r\nTo resolve this issue, users will need to uninstall McAfee SiteAdvisor/WebAdvisor, reboot the computer, and then reinstall McAfee SiteAdvisor/WebAdvisor. \r\n\r\nFor detailed instructions, please refer to the McAfee support knowledge base.","why":"Old versions of McAfee SiteAdvisor cause startup crashes starting with Firefox 48.0 beta.","name":"McAfee SiteAdvisor lower than 4.0","created":"2016-07-14T21:24:02Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.9.9","minVersion":"0","targetApplication":[]}],"id":"d727d8c5-3329-c98a-7c7e-38b0813ca516","last_modified":1480349204748},{"guid":"{2aab351c-ad56-444c-b935-38bffe18ad26}","prefs":[],"schema":1480349193877,"blockID":"i500","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946087","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Adobe Photo (malware)","created":"2013-12-04T15:29:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7a76d34-ddcd-155e-9fae-5967bd796041","last_modified":1480349204716},{"guid":"jid1-4P0kohSJxU1qGg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i488","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=942935","who":"All Firefox users who have version 1.2.50 of the Hola extension. Updating to the latest version should remove the block.","why":"Version 1.2.50 of the Hola extension is causing frequent crashes in Firefox. All users are strongly recommended to update to the latest version, which shouldn't have this problem.","name":"Hola, version 1.2.50","created":"2013-11-25T12:14:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.50","minVersion":"1.2.50","targetApplication":[]}],"id":"5c7f1635-b39d-4278-5f95-9042399c776e","last_modified":1480349204668},{"guid":"{0A92F062-6AC6-8180-5881-B6E0C0DC2CC5}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i864","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131220","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and makes unwanted settings changes, in violation of our Add-on Guidelines.","name":"BlockAndSurf","created":"2015-02-26T12:56:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"acb16d1c-6274-93a3-7c1c-7ed36ede64a9","last_modified":1480349204612},{"guid":"jid0-Y6TVIzs0r7r4xkOogmJPNAGFGBw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i322","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=847018","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:39:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"54df22cd-19ce-a7f0-63cc-ffe3113748b9","last_modified":1480349204532},{"guid":"trackerbird@bustany.org","prefs":[],"schema":1480349193877,"blockID":"i986","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1189264","who":"All Thunderbird users who have this version of the add-on installed on Thunderbird 38.0a2 and above.","why":"This add-on is causing consistent crashes on Thunderbird 38.0a2 and above.","name":"trackerbird 1.2.6","created":"2015-08-17T15:56:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.6","minVersion":"1.2.6","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"}]}],"id":"bb1c699e-8790-4528-0b6d-4f83b7a3152d","last_modified":1480349204041},{"guid":"{0134af61-7a0c-4649-aeca-90d776060cb3}","prefs":[],"schema":1480349193877,"blockID":"i448","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=912746","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"KeyBar add-on","created":"2013-09-13T16:15:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cf428416-4974-8bb4-7928-c0cb2cfe7957","last_modified":1480349203968},{"guid":"/^(firefox@vebergreat\\.net|EFGLQA@78ETGYN-0W7FN789T87\\.COM)$/","prefs":[],"schema":1480349193877,"blockID":"i564","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974104","who":"All Firefox users who have these add-ons installed. If you wish to continue using these add-ons, you can enable them in the Add-ons Manager.","why":"These add-ons are silently installed by the Free Driver Scout installer, in violation of our Add-on Guidelines.","name":"veberGreat and vis (Free Driver Scout bundle)","created":"2014-03-05T13:02:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"487538f1-698e-147e-6395-986759ceed7e","last_modified":1480349203902},{"guid":"69ffxtbr@PackageTracer_69.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i882","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1153001","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be malware, hijacking user's settings, in violation of the Add-on Guidelines.","name":"PackageTracer","created":"2015-04-10T16:18:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0d37b4e0-3c60-fdad-dd8c-59baff6eae87","last_modified":1480349203836},{"guid":"{ACAA314B-EEBA-48e4-AD47-84E31C44796C}","prefs":[],"schema":1480349193877,"blockID":"i496","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945530","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making settings changes that can't be easily reverted.","name":"DVDVideoSoft Menu","created":"2013-12-03T16:07:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"70d2c912-8d04-8065-56d6-d793b13d5f67","last_modified":1480349203779},{"guid":"jid1-4vUehhSALFNqCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i632","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033002","who":"All Firefox users who have this version of the add-on installed.","why":"Version 100.7 of the YouTube Plus Plus extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Plus Plus 100.7","created":"2014-07-01T13:16:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"100.7","minVersion":"100.7","targetApplication":[]}],"id":"8bef6026-6697-99cd-7c1f-812877c4211d","last_modified":1480349203658},{"guid":"{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}","prefs":[],"schema":1480349193877,"blockID":"i404","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb7a1dc7-16a0-4f70-8289-4df494e0d0fa","last_modified":1480349203633},{"guid":"P2@D.edu","prefs":[],"schema":1480349193877,"blockID":"i850","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128269","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"unIsaless","created":"2015-02-09T15:29:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"49536a29-fc7e-9fd0-f415-e15ac090fa56","last_modified":1480349203605},{"guid":"linksicle@linksicle.com","prefs":[],"schema":1480349193877,"blockID":"i472","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b5b15b3-6da7-cb7c-3c44-30b4fe079d52","last_modified":1480349203581},{"guid":"{377e5d4d-77e5-476a-8716-7e70a9272da0}","prefs":[],"schema":1480349193877,"blockID":"i398","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:15:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ea94df32-2a85-23da-43f7-3fc5714530ec","last_modified":1480349203519},{"guid":"{4933189D-C7F7-4C6E-834B-A29F087BFD23}","prefs":[],"schema":1480349193877,"blockID":"i437","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=900695","who":"All Firefox users.","why":"This add-on is widely reported to be malware.","name":"Win32.SMSWebalta (malware)","created":"2013-08-09T15:14:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cbef1357-d6bc-c8d3-7a82-44af6b1c390f","last_modified":1480349203486},{"guid":"{ADFA33FD-16F5-4355-8504-DF4D664CFE10}","prefs":[],"schema":1480349193877,"blockID":"i306","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844972","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed, bypassing our third-party opt-in screen, in violation of our Add-on Guidelines. It's also possible that it changes user settings without their consent.","name":"Nation Toolbar","created":"2013-02-28T12:56:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"017fd151-37ca-4646-4763-1d303fb918fa","last_modified":1480349203460},{"guid":"detgdp@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i884","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152614","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware, hijacking user settings, in violation of the Add-on Guidelines.","name":"Security Protection (malware)","created":"2015-04-10T16:21:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1b5cc88e-499d-2a47-d793-982d4c05e6ee","last_modified":1480349203433},{"guid":"/^(67314b39-24e6-4f05-99f3-3f88c7cddd17@6c5fa560-13a3-4d42-8e90-53d9930111f9\\.com|ffxtlbr@visualbee\\.com|{7aeae561-714b-45f6-ace3-4a8aed6e227b}|{7093ee04-f2e4-4637-a667-0f730797b3a0}|{53c4024f-5a2e-4f2a-b33e-e8784d730938})$/","prefs":[],"schema":1480349193877,"blockID":"i514","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947473","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by using multiple add-on IDs and making unwanted settings changes.","name":"VisualBee Toolbar","created":"2013-12-20T12:25:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f91eee1-7303-3f97-dfe6-1e897a156c7f","last_modified":1480349203408},{"guid":"FXqG@xeeR.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i720","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and changes settings without consent, in violation of the Add-on Guidelines.","name":"GoSSave","created":"2014-10-02T12:23:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8ebbc061-a4ff-b75b-ec42-eb17c42a2956","last_modified":1480349203341},{"guid":"{87934c42-161d-45bc-8cef-ef18abe2a30c}","prefs":[],"schema":1480349193877,"blockID":"i547","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=798621","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed and makes various unwanted changes, in violation of the Add-on Guidelines.","name":"Ad-Aware Security Toolbar","created":"2014-01-30T12:42:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.7.9999999999","minVersion":"0","targetApplication":[]}],"id":"bcfbc502-24c2-4699-7435-e4837118f05a","last_modified":1480349203310},{"guid":"kallow@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i495","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945426","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook Security Service (malware)","created":"2013-12-02T15:09:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1a2c37a9-e7cc-2d03-2043-098d36b8aca2","last_modified":1480349203247},{"guid":"support@lastpass.com","prefs":[],"schema":1480349193877,"blockID":"i1261","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1289907","who":"All users who install affected versions of this add-on - beta versions 4.0 to 4.1.20a from addons.mozilla.org or lastpass.com.","why":"LastPass have announced there are security issues that would allow a malicious website to perform some actions (e.g. deleting passwords) without the user's knowledge. Beta versions 4.0 to 4.1.20a of their add-on that were available from addons.mozilla.org are affected and Lastpass also distributed these versions direct from their website.","name":"LastPass addon","created":"2016-07-29T14:17:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.1.20a","minVersion":"4.0.0a","targetApplication":[]}],"id":"ffe94023-b4aa-87ac-962c-5beabe34b1a0","last_modified":1480349203208},{"guid":"008abed2-b43a-46c9-9a5b-a771c87b82da@1ad61d53-2bdc-4484-a26b-b888ecae1906.com","prefs":[],"schema":1480349193877,"blockID":"i528","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949565","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed.","name":"weDownload Manager Pro","created":"2013-12-20T14:40:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"da46065f-1c68-78f7-80fc-8ae07b5df68d","last_modified":1480349203131},{"guid":"{25dd52dc-89a8-469d-9e8f-8d483095d1e8}","prefs":[],"schema":1480349193877,"blockID":"i714","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Web Counselor","created":"2014-10-01T15:36:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e46c31ad-0ab3-e48a-47aa-9fa91b675fda","last_modified":1480349203066},{"guid":"{B1FC07E1-E05B-4567-8891-E63FBE545BA8}","prefs":[],"schema":1480349193877,"blockID":"i926","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:28:46Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"09868783-261a-ac24-059d-fc772218c1ba","last_modified":1480349202708},{"guid":"/^(torntv@torntv\\.com|trtv3@trtv\\.com|torntv2@torntv\\.com|e2fd07a6-e282-4f2e-8965-85565fcb6384@b69158e6-3c3b-476c-9d98-ae5838c5b707\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i529","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949559","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed.","name":"TornTV","created":"2013-12-20T14:46:03Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"040e5ec2-ea34-816a-f99f-93296ce845e8","last_modified":1480349202677},{"guid":"249911bc-d1bd-4d66-8c17-df533609e6d8@c76f3de9-939e-4922-b73c-5d7a3139375d.com","prefs":[],"schema":1480349193877,"blockID":"i532","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949672","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"Feven","created":"2013-12-20T15:02:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d32b850d-82d5-b63d-087c-fb2041b2c232","last_modified":1480349202631},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i704","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T14:49:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"0.*","minVersion":"0","targetApplication":[]}],"id":"79ea6621-b414-17a4-4872-bfc4af7fd428","last_modified":1480349202588},{"guid":"{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}","prefs":[],"schema":1480349193877,"blockID":"i429","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=899178","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that spreads spam through Facebook.","name":"Video Player 1.3 (malware)","created":"2013-07-30T14:31:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d98b2b76-4082-3387-ae33-971d973fa278","last_modified":1480349202541},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i648","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouTube Enhancer Plus extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Enhancer Plus, versions between 199.7.0 and 208.7.0","created":"2014-07-10T15:12:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.7.0","minVersion":"199.7.0","targetApplication":[]}],"id":"7e64d7fc-ff16-8687-dbd1-bc4c7dfc5097","last_modified":1480349202462},{"guid":"addon@defaulttab.com","prefs":[],"schema":1480349193877,"blockID":"i362","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=863387","who":"All users who have this add-on installed. Users who wish to enable it again can do so in the Add-ons Manager tab.","why":"Old versions of this add-on had been silently installed into users' systems, without showing the opt-in install page that is built into Firefox.","name":"Default Tab","created":"2013-06-06T12:57:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.4.4","minVersion":"0","targetApplication":[]}],"id":"df3fe753-5bae-bfb4-022b-6b6bfc534937","last_modified":1480349202429},{"guid":"{7D4F1959-3F72-49d5-8E59-F02F8AA6815D}","prefs":[],"schema":1480349193877,"blockID":"i394","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881447","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This is a companion add-on for the SweetPacks Toolbar which is blocked due to guideline violations.","name":"Updater By SweetPacks","created":"2013-06-25T12:40:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"851c2b8e-ea19-3a63-eac5-f931a8da5d6e","last_modified":1480349202341},{"guid":"g@uzcERQ6ko.net","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i776","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines","name":"GoSave","created":"2014-10-31T16:23:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ee1e1a44-b51b-9f12-819d-64c3e515a147","last_modified":1480349202307},{"guid":"ffxtlbr@incredibar.com","prefs":[],"schema":1480349193877,"blockID":"i318","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812264","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"IncrediBar","created":"2013-03-20T14:40:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9e84b07c-84d5-c932-85f2-589713d7e380","last_modified":1480349202280},{"guid":"M1uwW0@47z8gRpK8sULXXLivB.com","prefs":[],"schema":1480349193877,"blockID":"i870","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131159","who":"All users who have this add-on installed.","why":"This is a malicious add-on that goes by the the name \"Flash Player 11\".","name":"Flash Player 11 (malware)","created":"2015-03-04T14:34:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"71d961b2-37d1-d393-76f5-3afeef57e749","last_modified":1480349202252},{"guid":"jid1-qj0w91o64N7Eeg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i650","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouTube ALL HTML5 extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube ALL HTML5, versions between 39.5.1 and 47.0.4","created":"2014-07-10T15:14:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"47.0.4","minVersion":"39.5.1","targetApplication":[]}],"id":"b30b1f7a-2a30-a6cd-fc20-6c9cb23c7198","last_modified":1480349202186},{"guid":"4zffxtbr-bs@VideoDownloadConverter_4z.com","prefs":[],"schema":1480349193877,"blockID":"i507","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949266","who":"All Firefox users who have this add-on installed.","why":"Certain versions of this add-on contains an executable that is flagged by multiple tools as malware. Newer versions no longer use it.","name":"VideoDownloadConverter","created":"2013-12-12T15:37:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.75.3.25126","minVersion":"0","targetApplication":[]}],"id":"0a0f106a-ecc6-c537-1818-b36934943e91","last_modified":1480349202156},{"guid":"hdv@vovcacik.addons.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i656","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the High Definition Video extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"High Definition Video, version 102.0","created":"2014-07-10T15:22:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"102.0","minVersion":"102.0","targetApplication":[]}],"id":"972249b2-bba8-b508-2ead-c336631135ac","last_modified":1480349202125},{"guid":"@video_downloader_pro","prefs":[],"schema":1480349193877,"blockID":"i1265","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1298335","who":"Users of versions of 1.2.1 to 1.2.5 inclusive.","why":"Versions 1.2.1 to 1.2.5 of Video Downloader Pro included code that violated our polices - affected versions send every visited url to a remote server without the user's consent. Versions older than 1.2.1 and more recent than 1.2.5 are okay.","name":"Video Downloader Pro","created":"2016-08-26T18:26:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.5","minVersion":"1.2.1","targetApplication":[]}],"id":"ff9c8def-7d50-66b4-d42a-f9a4b04bd224","last_modified":1480349202099},{"guid":"contato@facefollow.net","prefs":[],"schema":1480349193877,"blockID":"i509","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950846","who":"All Firefox users who have this add-on installed.","why":"This add-on spams users' Facebook accounts.","name":"Face follow","created":"2013-12-16T16:15:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"56f15747-af8c-342c-6877-a41eeacded84","last_modified":1480349202067},{"guid":"wecarereminder@bryan","prefs":[],"schema":1480349193877,"blockID":"i666","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=818614","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is being silently installed by various software packages, in violation of the Add-on Guidelines.","name":"We-Care Reminder","created":"2014-07-10T16:18:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"51e0ead7-144c-c1f4-32f2-25fc5fcde870","last_modified":1480349202039},{"guid":"/^({83a8ce1b-683c-4784-b86d-9eb601b59f38}|{ef1feedd-d8da-4930-96f1-0a1a598375c6}|{79ff1aae-701f-4ca5-aea3-74b3eac6f01b}|{8a184644-a171-4b05-bc9a-28d75ffc9505}|{bc09c55d-0375-4dcc-836e-0e3c8addfbda}|{cef81415-2059-4dd5-9829-1aef3cf27f4f})$/","prefs":[],"schema":1480349193877,"blockID":"i526","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and uses multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:12:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9dfa4e92-bbf2-66d1-59a9-51402d1d226c","last_modified":1480349202010},{"guid":"{d9284e50-81fc-11da-a72b-0800200c9a66}","prefs":[],"schema":1480349193877,"blockID":"i806","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1106948","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable the add-on in the Add-on Manager.","why":"Starting with Firefox 34, current versions of the Yoono add-on cause all tabs to appear blank.","name":"Yoono","created":"2014-12-16T08:35:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.7.34","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"34.0a1"}]}],"id":"ccdceb04-3083-012f-9d9f-aac85f10b494","last_modified":1480349201976},{"guid":"{f2548724-373f-45fe-be6a-3a85e87b7711}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i768","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088726","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astro New Tab","created":"2014-10-30T14:52:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8510e9e2-c7d8-90d0-a2ff-eb09293acc6e","last_modified":1480349201854},{"guid":"KSqOiTeSJEDZtTGuvc18PdPmYodROmYzfpoyiCr2@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1032","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211172","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video Player (malware)","created":"2015-10-05T16:22:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3d9188ac-235f-773a-52a2-261b3ea9c03c","last_modified":1480349201504},{"guid":"{849ded12-59e9-4dae-8f86-918b70d213dc}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i708","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1047102","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes homepage and search settings without the user's consent, in violation of the Add-on Guidelines.","name":"Astromenda New Tab","created":"2014-09-02T16:29:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a319bfee-464f-1c33-61ad-738c52842fbd","last_modified":1480349201453},{"guid":"grjkntbhr@hgergerherg.com","prefs":[],"schema":1480349193877,"blockID":"i1018","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208196","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"GreenPlayer (malware)","created":"2015-09-24T16:04:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9c47d940-bdd9-729f-e32e-1774d87f24b5","last_modified":1480349201425},{"guid":"quick_start@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i588","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011316","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware that is installed without user consent.","name":"Quick Start (malware)","created":"2014-06-03T15:53:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2affbebe-8776-3edb-28b9-237cb8b85f97","last_modified":1480349201398},{"guid":"/^(matchersite(pro(srcs?)?)?\\@matchersite(pro(srcs?)?)?\\.com)|((pro)?sitematcher(_srcs?|pro|site|sitesrc|-generic)?\\@(pro)?sitematcher(_srcs?|pro|site|sitesrc|-generic)?\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i668","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1039892","who":"All Firefox users who have any of these add-ons installed. User who wish to continue using these add-ons can enable them in the Add-ons Manager.","why":"This is a group of add-ons that are being distributed under multiple different IDs and likely being silently installed, in violation of the Add-on Guidelines.","name":"Site Matcher","created":"2014-07-17T14:35:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"52e1a2de-ab35-be27-4810-334f681ccc4a","last_modified":1480349201372},{"guid":"{EEF73632-A085-4fd3-A778-ECD82C8CB297}","prefs":[],"schema":1480349193877,"blockID":"i165","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec-M (malware)","created":"2012-10-29T16:41:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e5ecd02a-20ee-749b-d5cf-3d74d1173a1f","last_modified":1480349201262},{"guid":"firefox-extension@mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i688","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1049533","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hides itself under the name Java_plugin, among others.","name":"FinFisher (malware)","created":"2014-08-06T17:13:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98aca74a-69c7-9960-cccc-096a4a4adc6c","last_modified":1480349201235},{"guid":"jid1-vW9nopuIAJiRHw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i570","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=990291","who":"All Firefox users who have this add-on installed. Those who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, reverts settings changes to enforce its own, and is also causing stability problems in Firefox, all in violation of the Add-on Guidelines.","name":"SmileysWeLove","created":"2014-03-31T16:17:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bf2abd66-f910-650e-89aa-cd1d5c2f8a89","last_modified":1480349201204},{"guid":"87aukfkausiopoawjsuifhasefgased278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1050","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1220461","who":"All users who have this add-on installed.","why":"This is a malicious add-on that poses as a video update and hijacks Facebook accounts.","name":"Trace Video (malware)","created":"2015-11-02T14:53:21Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cb4cfac0-79c2-0fbf-206a-324aa3abbea5","last_modified":1480349201157},{"guid":"{e44a1809-4d10-4ab8-b343-3326b64c7cdd}","prefs":[],"schema":1480349193877,"blockID":"i451","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=916966","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, manipulating settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Entrusted","created":"2013-09-18T16:33:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ad5f53ed-7a43-cb1f-cbd7-41808fac1791","last_modified":1480349201128},{"guid":"{21EAF666-26B3-4A3C-ABD0-CA2F5A326744}","prefs":[],"schema":1480349193877,"blockID":"i620","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024752","who":"All Firefox users who have this add-on installed.","why":"This add-on is probably silently installed, and is causing significant stability issues for users, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-06-12T15:27:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2d8833db-01a7-a758-080f-19e47abc54cb","last_modified":1480349201096},{"guid":"{1FD91A9C-410C-4090-BBCC-55D3450EF433}","prefs":[],"schema":1480349193877,"blockID":"i338","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844979","who":"All Firefox users who have this add-on installed.","why":"This extension overrides search settings, and monitors any further changes done to them so that they can be reverted. This violates our add-on guidelines.","name":"DataMngr (malware)","created":"2013-04-24T11:30:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2e35995f-bec6-aa2b-3372-346d3325f72e","last_modified":1480349201059},{"guid":"9598582LLKmjasieijkaslesae@jetpack","prefs":[],"schema":1480349193877,"blockID":"i996","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201165","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Secure Player (malware)","created":"2015-09-07T13:50:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"52f9c6e7-f7d5-f52e-cc35-eb99ef8b4b6a","last_modified":1480349201029},{"guid":"{bf7380fa-e3b4-4db2-af3e-9d8783a45bfc}","prefs":[],"schema":1480349193877,"blockID":"i406","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=776404","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. This violates our Add-on Guidelines.","name":"uTorrentBar","created":"2013-06-27T10:46:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3bcefc4b-110c-f3b8-17ad-f9fc97c1120a","last_modified":1480349201000},{"guid":"{ce7e73df-6a44-4028-8079-5927a588c948}","prefs":[],"schema":1480349193877,"blockID":"i117","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=781269","who":"All Firefox users who have this add-on installed.","why":"The Search By Image (by Google) extension causes very high CPU utilization during regular browsing, often damaging user experience significantly, in a way that is very difficult to associate with the extension.\r\n\r\nUsers who want to continue using the add-on regardless of its performance impact can enable it in the Add-ons Manager.","name":"Search By Image (by Google)","created":"2012-08-10T08:50:52Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.8","minVersion":"0","targetApplication":[]}],"id":"fb1f9aed-2f1f-3e2c-705d-3b34ca9168b6","last_modified":1480349200972},{"guid":"{424b0d11-e7fe-4a04-b7df-8f2c77f58aaf}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i800","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda NT","created":"2014-12-15T10:51:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"07bdf6aa-cfc8-ed21-6b36-6f90af02b169","last_modified":1480349200939},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i618","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:25:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.31.*","minVersion":"3.15.31","targetApplication":[]}],"id":"825feb43-d6c2-7911-4189-6f589f612c34","last_modified":1480349200911},{"guid":"{167d9323-f7cc-48f5-948a-6f012831a69f}","prefs":[],"schema":1480349193877,"blockID":"i262","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812303","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and doesn't do much more than changing the users' settings, without reverting them on removal.","name":"WhiteSmoke (malware)","created":"2013-01-29T13:33:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a8f249fe-3db8-64b8-da89-7b584337a7af","last_modified":1480349200885},{"guid":"/^({988919ff-0cd8-4d0c-bc7e-60d55a49eb64}|{494b9726-9084-415c-a499-68c07e187244}|{55b95864-3251-45e9-bb30-1a82589aaff1}|{eef3855c-fc2d-41e6-8d91-d368f51b3055}|{90a1b331-c2b4-4933-9f63-ba7b84d60d58}|{d2cf9842-af95-48cd-b873-bfbb48cd7f5e})$/","prefs":[],"schema":1480349193877,"blockID":"i541","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:09:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"36196aed-9d0d-ebee-adf1-d1f7fadbc48f","last_modified":1480349200819},{"guid":"{29b136c9-938d-4d3d-8df8-d649d9b74d02}","prefs":[],"schema":1480349193877,"blockID":"i598","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011322","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, in violation with our Add-on Guidelines.","name":"Mega Browse","created":"2014-06-12T13:21:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"63b1c965-27c3-cd06-1b76-8721add39edf","last_modified":1480349200775},{"guid":"{6e7f6f9f-8ce6-4611-add2-05f0f7049ee6}","prefs":[],"schema":1480349193877,"blockID":"i868","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1086574","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Word Proser","created":"2015-02-26T14:58:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f54797da-cdcd-351a-c95e-874b64b0d226","last_modified":1480349200690},{"guid":"{02edb56b-9b33-435b-b7df-b2843273a694}","prefs":[],"schema":1480349193877,"blockID":"i438","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=896581","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It is installed bypassing the Firefox opt-in screen, and manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"KeyBar Toolbar","created":"2013-08-09T15:27:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"896710d2-5a65-e9b0-845b-05aa72c2bd51","last_modified":1480349200338},{"guid":"{e1aaa9f8-4500-47f1-9a0a-b02bd60e4076}","prefs":[],"schema":1480349193877,"blockID":"i646","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Youtube Video Replay extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Youtube Video Replay, version 178.7.0","created":"2014-07-10T15:10:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"178.7.0","minVersion":"178.7.0","targetApplication":[]}],"id":"ac5d1083-6753-bbc1-a83d-c63c35371b22","last_modified":1480349200312},{"guid":"{1cdbda58-45f8-4d91-b566-8edce18f8d0a}","prefs":[],"schema":1480349193877,"blockID":"i724","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080835","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Counselor Pro","created":"2014-10-13T16:00:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7b70bd36-d2f7-26fa-9038-8b8dd132cd81","last_modified":1480349200288},{"guid":"{b12785f5-d8d0-4530-a3ea-5c4263b85bef}","prefs":[],"schema":1480349193877,"blockID":"i988","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1161573","who":"All users who have this add-on installed. Those who wish continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on overrides user's preferences without consent, in violation of the Add-on Guidelines.","name":"Hero Fighter Community Toolbar","created":"2015-08-17T16:04:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e6d73f2-e8e3-af69-866e-30d3977b09e4","last_modified":1480349200171},{"guid":"{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}","prefs":[],"schema":1480349193877,"blockID":"i39","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=665775","who":"Users of MediaBar versions 4.3.1.00 and below in all versions of Firefox.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"MediaBar","created":"2011-07-19T10:18:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.3.1.00","minVersion":"0.1","targetApplication":[]}],"id":"e928a115-9d8e-86a4-e2c7-de39627bd9bf","last_modified":1480349200047},{"guid":"{9edd0ea8-2819-47c2-8320-b007d5996f8a}","prefs":["browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i684","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033857","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is believed to be silently installed in Firefox, in violation of the Add-on Guidelines.","name":"webget","created":"2014-08-06T13:33:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d38561f5-370f-14be-1443-a74dad29b1f3","last_modified":1480349199962},{"guid":"/^({ad9a41d2-9a49-4fa6-a79e-71a0785364c8})|(ffxtlbr@mysearchdial\\.com)$/","prefs":["browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i670","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036740","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on has been repeatedly been silently installed into users' systems, and is known for changing the default search without user consent, in violation of the Add-on Guidelines.","name":"MySearchDial","created":"2014-07-18T15:47:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a04075e6-5df2-2e1f-85a6-3a0171247349","last_modified":1480349199927},{"guid":"odtffplugin@ibm.com","prefs":[],"schema":1480349193877,"blockID":"i982","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190630","who":"All users who have these versions installed. The latest versions of this add-on aren't blocked, so updating to them should be sufficient to fix this problem.","why":"Certain versions of the IBM Remote Control add-on could leave a machine vulnerable to run untrusted code.","name":"IBM Endpoint Manager for Remote Control 9.0.1.1 to 9.0.1.100","created":"2015-08-11T11:25:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.0.1.100","minVersion":"9.0.1.1","targetApplication":[]}],"id":"f6e3e5d2-9331-1097-ba4b-cf2e484b7187","last_modified":1480349199886},{"guid":"support@todoist.com","prefs":[],"schema":1480349193877,"blockID":"i1030","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1205479","who":"All users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is sending all sites visited by the user to a remote server, additionally doing so in an unsafe way.","name":"Todoist","created":"2015-10-01T16:53:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.9","minVersion":"0","targetApplication":[]}],"id":"d0a84aab-0661-b3c5-c184-a2fd3f9dfb9c","last_modified":1480349199850},{"guid":"/^({1f43c8af-e9e4-4e5a-b77a-f51c7a916324}|{3a3bd700-322e-440a-8a6a-37243d5c7f92}|{6a5b9fc2-733a-4964-a96a-958dd3f3878e}|{7b5d6334-8bc7-4bca-a13e-ff218d5a3f17}|{b87bca5b-2b5d-4ae8-ad53-997aa2e238d4}|{bf8e032b-150f-4656-8f2d-6b5c4a646e0d})$/","prefs":[],"schema":1480349193877,"blockID":"i1136","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hides itself from view and disables various security features in Firefox.","name":"Watcher (malware)","created":"2016-03-04T17:56:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a2d0378f-ebe4-678c-62d8-2e4c6a613c17","last_modified":1480349199818},{"guid":"liiros@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i814","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119657","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent and performs unwanted operations.","name":"One Tab (malware)","created":"2015-01-09T12:49:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"387c054d-cc9f-7ebd-c814-b4c1fbcb2880","last_modified":1480349199791},{"guid":"youtubeunblocker@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1128","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that is being exploited through this website (unblocker.yt) to change security settings in Firefox and install malicious add-ons.","name":"YouTube Unblocker","created":"2016-03-01T21:18:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3395fce1-42dd-e31a-1466-2da3f32456a0","last_modified":1480349199768},{"guid":"{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}","prefs":[],"schema":1480349193877,"blockID":"i916","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:57:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"94fba774-c4e6-046a-bc7d-ede787a9d0fe","last_modified":1480349199738},{"guid":"{b64982b1-d112-42b5-b1e4-d3867c4533f8}","prefs":[],"schema":1480349193877,"blockID":"i167","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=805973","who":"All Firefox users who have this add-on installed.","why":"This add-on is a frequent cause for browser crashes and other problems.","name":"Browser Manager","created":"2012-10-29T17:17:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"00bbe501-2d27-7a1c-c344-6eea1c707473","last_modified":1480349199673},{"guid":"{58bd07eb-0ee0-4df0-8121-dc9b693373df}","prefs":[],"schema":1480349193877,"blockID":"i286","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=842206","who":"All Firefox users who have this extension installed.","why":"This extension is malicious and is installed under false pretenses, causing problems for many Firefox users. Note that this is not the same BrowserProtect extension that is listed on our add-ons site. That one is safe to use.","name":"Browser Protect / bProtector (malware)","created":"2013-02-18T10:54:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b40a60d3-b9eb-09eb-bb02-d50b27aaac9f","last_modified":1480349199619},{"guid":"trtv3@trtv.com","prefs":[],"schema":1480349193877,"blockID":"i465","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845610","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"TornTV","created":"2013-11-01T15:21:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3d4d8a33-2eff-2556-c699-9be0841a8cd4","last_modified":1480349199560},{"guid":"youtube@downloader.yt","prefs":[],"schema":1480349193877,"blockID":"i1231","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1278932","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that can being exploited through this website (downloader.yt) to change security settings in Firefox and/or install malicious add-ons. \r\n","name":"YouTube downloader","created":"2016-06-09T14:50:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8514eaee-850c-e27a-a058-8badeeafc26e","last_modified":1480349199528},{"guid":"low_quality_flash@pie2k.com","prefs":[],"schema":1480349193877,"blockID":"i658","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Low Quality Flash extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Low Quality Flash, versions between 46.2 and 47.1","created":"2014-07-10T15:27:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"47.1","minVersion":"46.2","targetApplication":[]}],"id":"b869fae6-c18c-0d39-59a2-603814656404","last_modified":1480349199504},{"guid":"{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}","prefs":[],"schema":1480349193877,"blockID":"i439","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=902569","who":"All Firefox users who have this add-on installed.","why":"This is another instance of the previously blocked Mixi DJ add-on, which doesn't follow our Add-on Guidelines. If you wish to continue using it, it can be enabled in the Add-ons Manager.","name":"Mixi DJ V45","created":"2013-08-09T16:08:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e81c31fc-265e-61b9-d4c1-0e2f31f1652e","last_modified":1480349199478},{"guid":"/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/","prefs":[],"schema":1480349193877,"blockID":"i624","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947482","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is known to change user settings without their consent, is distributed under multiple add-on IDs, and is also correlated with reports of tab functions being broken in Firefox, in violation of the Add-on Guidelines.\r\n","name":"WiseConvert","created":"2014-06-18T13:50:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ed57d7a6-5996-c7da-8e07-1ad125183e84","last_modified":1480349199446},{"guid":"{f894a29a-f065-40c3-bb19-da6057778493}","prefs":[],"schema":1480349193877,"blockID":"i742","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080817","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be silently installed into users' systems, and changes settings without consent, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-10-17T15:46:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39d8334e-4b7c-4336-2d90-e6aa2d783967","last_modified":1480349199083},{"guid":"plugin@analytic-s.com","prefs":[],"schema":1480349193877,"blockID":"i467","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935797","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Analytics","created":"2013-11-07T14:08:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ffbed3f3-e5c9-bc6c-7530-f68f47b7efd6","last_modified":1480349199026},{"guid":"{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}","prefs":[],"schema":1480349193877,"blockID":"i678","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=895668","who":"All Firefox users who have this add-on installed. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on is generally silently installed, in violation of the Add-on Guidelines.","name":"DataMngr","created":"2014-07-23T14:12:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"151021fc-ce4e-a734-e075-4ece19610f64","last_modified":1480349198947},{"guid":"HxLVJK1ioigz9WEWo8QgCs3evE7uW6LEExAniBGG@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1036","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211170","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Mega Player (malware)","created":"2015-10-05T16:37:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32e34b41-a73c-72d4-c96c-136917ad1d4d","last_modified":1480349198894},{"guid":"{6af08a71-380e-42dd-9312-0111d2bc0630}","prefs":[],"schema":1480349193877,"blockID":"i822","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1126353","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware, hiding itself in the Add-ons Manager, and keeping track of certain user actions.","name":"{6af08a71-380e-42dd-9312-0111d2bc0630} (malware)","created":"2015-01-27T09:50:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"96d0c12b-a6cf-4539-c1cf-a1c75c14ff24","last_modified":1480349198826},{"guid":"colmer@yopmail.com","prefs":[],"schema":1480349193877,"blockID":"i550","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=968445","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Video Plugin Facebook (malware)","created":"2014-02-06T15:49:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c394d10b-384e-cbd0-f357-9c521715c373","last_modified":1480349198744},{"guid":"fplayer@adobe.flash","prefs":[],"schema":1480349193877,"blockID":"i444","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=909433","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware disguised as the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-08-26T14:49:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c6557989-1b59-72a9-da25-b816c4a4c723","last_modified":1480349198667},{"guid":"ascsurfingprotection@iobit.com","prefs":[],"schema":1480349193877,"blockID":"i740","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963776","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Advanced SystemCare Surfing Protection","created":"2014-10-17T15:39:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4405f99d-c9b7-c496-1b45-268163ce29b7","last_modified":1480349198637},{"guid":"{6E19037A-12E3-4295-8915-ED48BC341614}","prefs":[],"schema":1480349193877,"blockID":"i24","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=615518","who":"Users of RelevantKnowledge version 1.3.328.4 and older in Firefox 4 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"comScore RelevantKnowledge","created":"2011-03-02T17:42:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.328.4","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"7c189c5e-f95b-0aef-e9e3-8e879336503b","last_modified":1480349198606},{"guid":"crossriderapp4926@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i91","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=754648","who":"All Firefox users who have installed this add-on.","why":"Versions of this add-on prior to 0.81.44 automatically post message to users' walls and hide them from their view. Version 0.81.44 corrects this.","name":"Remove My Timeline (malware)","created":"2012-05-14T14:16:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.81.43","minVersion":"0","targetApplication":[]}],"id":"5ee3e72e-96fb-c150-fc50-dd581e960963","last_modified":1480349198547},{"guid":"/^(93abedcf-8e3a-4d02-b761-d1441e437c09@243f129d-aee2-42c2-bcd1-48858e1c22fd\\.com|9acfc440-ac2d-417a-a64c-f6f14653b712@09f9a966-9258-4b12-af32-da29bdcc28c5\\.com|58ad0086-1cfb-48bb-8ad2-33a8905572bc@5715d2be-69b9-4930-8f7e-64bdeb961cfd\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i544","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949596","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is in violation of the Add-on Guidelines, using multiple add-on IDs and potentially doing other unwanted activities.","name":"SuperLyrics","created":"2014-01-30T11:51:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d8d25967-9814-3b65-0787-a0525c16e11e","last_modified":1480349198510},{"guid":"wHO@W9.net","prefs":[],"schema":1480349193877,"blockID":"i980","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1192468","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"BestSavEFOrYoU (malware)","created":"2015-08-11T11:20:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4beb917f-68f2-1f91-beed-dff6d83006f8","last_modified":1480349198483},{"guid":"frhegnejkgner@grhjgewfewf.com","prefs":[],"schema":1480349193877,"blockID":"i1040","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1212451","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Async Codec (malware)","created":"2015-10-07T13:03:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb6ab4ce-5517-bd68-2cf7-a93a109a528a","last_modified":1480349198458},{"guid":"firefox@luckyleap.net","prefs":[],"schema":1480349193877,"blockID":"i471","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a9e04c7-5e64-6297-8442-2816915aad77","last_modified":1480349198433},{"guid":"auto-plugin-checker@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1210","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1270175","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on reports every visited URL to a third party without disclosing it to the user.","name":"auto-plugin-checker","created":"2016-05-04T16:25:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e202419-5318-2025-b579-c828af24a06e","last_modified":1480349198401},{"guid":"lugcla21@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i432","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=902072","who":"All Firefox users who have this add-on installed.","why":"This add-on includes malicious code that spams users' Facebook accounts with unwanted messages.","name":"FB Color Changer (malware)","created":"2013-08-06T13:16:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b6943f35-9429-1f8e-bf8e-fe37979fe183","last_modified":1480349198372},{"guid":"{99079a25-328f-4bd4-be04-00955acaa0a7}","prefs":[],"schema":1480349193877,"blockID":"i402","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"16008331-8b47-57c8-a6f7-989914d1cb8a","last_modified":1480349198341},{"guid":"{81b13b5d-fba1-49fd-9a6b-189483ac548a}","prefs":[],"schema":1480349193877,"blockID":"i473","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:43Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"76debc7b-b875-6da4-4342-1243cbe437f6","last_modified":1480349198317},{"guid":"{e935dd68-f90d-46a6-b89e-c4657534b353}","prefs":[],"schema":1480349193877,"blockID":"i732","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Sites Pro","created":"2014-10-16T16:38:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"97fdc235-ac1a-9f20-1b4a-17c2f0d89ad1","last_modified":1480349198260},{"guid":"{32da2f20-827d-40aa-a3b4-2fc4a294352e}","prefs":[],"schema":1480349193877,"blockID":"i748","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963787","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Start Page","created":"2014-10-17T16:02:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6c980c8e-4a3c-7912-4a3a-80add457575a","last_modified":1480349198223},{"guid":"chinaescapeone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i431","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=901770","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that uses a deceptive name and hijacks social networks.","name":"F-Secure Security Pack (malware)","created":"2013-08-05T16:43:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fbd89a9d-9c98-8481-e4cf-93e327ca8be1","last_modified":1480349198192},{"guid":"{cc6cc772-f121-49e0-b1f0-c26583cb0c5e}","prefs":[],"schema":1480349193877,"blockID":"i716","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Counselor","created":"2014-10-02T12:12:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"debcd28c-884b-ca42-d983-6fabf91034dd","last_modified":1480349198148},{"guid":"{906000a4-88d9-4d52-b209-7a772970d91f}","prefs":[],"schema":1480349193877,"blockID":"i474","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"326d05b9-ace7-67c6-b094-aad926c185a5","last_modified":1480349197744},{"guid":"{A34CAF42-A3E3-11E5-945F-18C31D5D46B0}","prefs":["security.csp.enable","security.fileuri.strict_origin_policy","security.mixed_content.block_active_content"],"schema":1480349193877,"blockID":"i1227","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1274995","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on downgrades the security of all iframes from https to http and changes important Firefox security preferences.","name":"Mococheck WAP browser","created":"2016-05-31T15:45:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2230a5ce-a8f8-a20a-7974-3b960a03aba9","last_modified":1480349197699},{"guid":"{AB2CE124-6272-4b12-94A9-7303C7397BD1}","prefs":[],"schema":1480349193877,"blockID":"i20","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=627278","who":"Users of Skype extension versions below 5.2.0.7165 for all versions of Firefox.","why":"This add-on causes a high volume of Firefox crashes and introduces severe performance issues. Please update to the latest version. For more information, please read our announcement.","name":"Skype extension","created":"2011-01-20T18:39:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.2.0.7164","minVersion":"0.1","targetApplication":[]}],"id":"60e16015-1803-197a-3241-484aa961d18f","last_modified":1480349197667},{"guid":"f6682b47-e12f-400b-9bc0-43b3ccae69d1@39d6f481-b198-4349-9ebe-9a93a86f9267.com","prefs":[],"schema":1480349193877,"blockID":"i682","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1043017","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed, in violation of the Add-on Guidelines.","name":"enformation","created":"2014-08-04T16:07:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a7ae65cd-0869-67e8-02f8-6d22c56a83d4","last_modified":1480349197636},{"guid":"rally_toolbar_ff@bulletmedia.com","prefs":[],"schema":1480349193877,"blockID":"i537","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950267","who":"All Firefox users who have this extension installed. If you want to continue using it, you can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing it.","name":"Rally Toolbar","created":"2014-01-23T15:51:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4ac6eb63-b51a-3296-5b02-bae77f424032","last_modified":1480349197604},{"guid":"x77IjS@xU.net","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i774","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines\r\n","name":"YoutubeAdBlocke","created":"2014-10-31T16:22:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4771da14-bcf2-19b1-3d71-bc61a1c7d457","last_modified":1480349197578},{"guid":"{49c53dce-afa0-49a1-a08b-2eb8e8444128}","prefs":[],"schema":1480349193877,"blockID":"i441","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844985","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"ytbyclick","created":"2013-08-09T16:58:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f08d720-58c2-6acb-78ad-7af45c82c90b","last_modified":1480349197550},{"guid":"searchengine@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i886","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152555","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on appears to be malware, being silently installed and hijacking user settings, in violation of the Add-on Guidelines.","name":"Search Enginer","created":"2015-04-10T16:25:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"46de4f6e-2b29-7334-ebbb-e0048f114f7b","last_modified":1480349197525},{"guid":"{bb7b7a60-f574-47c2-8a0b-4c56f2da9802}","prefs":[],"schema":1480349193877,"blockID":"i754","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080850","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"AdvanceElite","created":"2014-10-17T16:27:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f222ceb2-9b69-89d1-8dce-042d8131a12e","last_modified":1480349197500},{"guid":"/^(test3@test.org|test2@test.org|test@test.org|support@mozilla.org)$/","prefs":[],"schema":1480349193877,"blockID":"i1119","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1242721","who":"All users who have these add-ons installed.","why":"These add-ons are malicious, or at least attempts at being malicious, using misleading names and including risky code.","name":"test.org add-ons (malware)","created":"2016-01-25T13:31:43Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"afd2a0d7-b050-44c9-4e45-b63696d9b22f","last_modified":1480349197468},{"guid":"/^((34qEOefiyYtRJT@IM5Munavn\\.com)|(Mro5Fm1Qgrmq7B@ByrE69VQfZvZdeg\\.com)|(KtoY3KGxrCe5ie@yITPUzbBtsHWeCdPmGe\\.com)|(9NgIdLK5Dq4ZMwmRo6zk@FNt2GCCLGyUuOD\\.com)|(NNux7bWWW@RBWyXdnl6VGls3WAwi\\.com)|(E3wI2n@PEHTuuNVu\\.com)|(2d3VuWrG6JHBXbQdbr@3BmSnQL\\.com))$/","prefs":[],"schema":1480349193877,"blockID":"i324","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=841791","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:48:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5be3a399-af3e-644e-369d-628273b3fdc2","last_modified":1480349197432},{"guid":"axtara__web@axtara.com","prefs":[],"schema":1480349193877,"blockID":"i1263","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have version 1.1.1 or less of this add-on installed.","why":"Old versions of this add-on contained code from YouTube Unblocker, which was originally blocked due to malicious activity. Version 1.1.2 is now okay.","name":"AXTARA Search (pre 1.1.2)","created":"2016-08-17T16:47:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.1.1","minVersion":"0","targetApplication":[]}],"id":"c58be1c9-3d63-a948-219f-e3225e1eec8e","last_modified":1480349197404},{"guid":"{8f894ed3-0bf2-498e-a103-27ef6e88899f}","prefs":[],"schema":1480349193877,"blockID":"i792","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ExtraW","created":"2014-11-26T13:49:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bebc9e15-59a1-581d-0163-329d7414edff","last_modified":1480349197368},{"guid":"profsites@pr.com","prefs":[],"schema":1480349193877,"blockID":"i734","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.\r\n","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ProfSites","created":"2014-10-16T16:39:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0d6d84d7-0b3f-c5ab-57cc-6b66b0775a23","last_modified":1480349197341},{"guid":"{872b5b88-9db5-4310-bdd0-ac189557e5f5}","prefs":[],"schema":1480349193877,"blockID":"i497","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945530","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making settings changes that can't be easily reverted.","name":"DVDVideoSoft Menu","created":"2013-12-03T16:08:09Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e8da89c4-c585-77e4-9872-591d20723a7e","last_modified":1480349197240},{"guid":"123456789@offeringmedia.com","prefs":[],"schema":1480349193877,"blockID":"i664","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that attempts to hide itself by impersonating the Adobe Flash plugin.","name":"Taringa MP3 / Adobe Flash","created":"2014-07-10T15:41:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d0a7dda-d92a-c8e2-21be-c92b0a88ac8d","last_modified":1480349197208},{"guid":"firefoxdav@icloud.com","prefs":[],"schema":1480349193877,"blockID":"i1214","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1271358","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on is causing frequent and persistent crashing.","name":"iCloud Bookmarks","created":"2016-05-17T16:55:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.4.22","minVersion":"0","targetApplication":[]}],"id":"2dddd7a7-b081-45e2-3eeb-2a7f76a1465f","last_modified":1480349197172},{"guid":"youplayer@addons.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i660","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouPlayer extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouPlayer, versions between 79.9.8 and 208.0.1","created":"2014-07-10T15:31:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.0.1","minVersion":"79.9.8","targetApplication":[]}],"id":"82dca22b-b889-5d9d-3fc9-b2184851f2d1","last_modified":1480349197136},{"guid":"{df6bb2ec-333b-4267-8c4f-3f27dc8c6e07}","prefs":[],"schema":1480349193877,"blockID":"i487","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=940681","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Facebook 2013 (malware)","created":"2013-11-19T14:59:45Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5867c409-b342-121e-3c3b-426e2f0ba1d4","last_modified":1480349197109},{"guid":"/^({4e988b08-8c51-45c1-8d74-73e0c8724579}|{93ec97bf-fe43-4bca-a735-5c5d6a0a40c4}|{aed63b38-7428-4003-a052-ca6834d8bad3}|{0b5130a9-cc50-4ced-99d5-cda8cc12ae48}|{C4CFC0DE-134F-4466-B2A2-FF7C59A8BFAD})$/","prefs":[],"schema":1480349193877,"blockID":"i524","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947481","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"SweetPacks","created":"2013-12-20T13:43:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1a3a26a2-cdaa-e5ba-f6ac-47b98ae2cc26","last_modified":1480349197082},{"guid":"foxyproxy@eric.h.jung","prefs":[],"schema":1480349193877,"blockID":"i950","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1183890","who":"All users who have this add-on installed on Thunderbird 38 and above.","why":"This add-on is causing consistent startup crashes on Thunderbird 38 and above.","name":"FoxyProxy Standard for Thunderbird","created":"2015-07-15T09:34:44Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.5.5","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"},{"guid":"{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}","maxVersion":"*","minVersion":"2.35"}]}],"id":"5ee8203d-bea2-6cd5-9ba0-d1922ffb3d21","last_modified":1480349197056},{"guid":"{82AF8DCA-6DE9-405D-BD5E-43525BDAD38A}","prefs":[],"schema":1480349193877,"blockID":"i1056","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1225639","who":"All users who have this add-on installed in Firefox 43 and above. User who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is associated with frequent shutdown crashes in Firefox.","name":"Skype Click to Call","created":"2015-11-17T14:03:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.5.0.9082","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"43.0a1"}]}],"id":"484f8386-c415-7499-a8a0-f4e16f5a142f","last_modified":1480349197027},{"guid":"{22119944-ED35-4ab1-910B-E619EA06A115}","prefs":[],"schema":1480349193877,"blockID":"i45","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=699134","who":"Users of version 7.9.20.6 of RoboForm Toolbar and earlier on Firefox 48 and above.","why":"Older versions of the RoboForm Toolbar add-on are causing crashes in Firefox 48 and above. The developer has released a fix, available in versions 7.9.21+.","name":"Roboform","created":"2011-11-19T06:14:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.9.20.6","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"8.0a1"}]}],"id":"5f7f9e13-d3e8-ea74-8341-b83e36d67d94","last_modified":1480349196995},{"guid":"{87b5a11e-3b54-42d2-9102-0a7cb1f79ebf}","prefs":[],"schema":1480349193877,"blockID":"i838","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128327","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"Cyti Web (malware)","created":"2015-02-06T14:29:12Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ba0e57c-4c0c-4eb6-26e7-c2016769c343","last_modified":1480349196965},{"guid":"/^({bf67a47c-ea97-4caf-a5e3-feeba5331231}|{24a0cfe1-f479-4b19-b627-a96bf1ea3a56})$/","prefs":[],"schema":1480349193877,"blockID":"i542","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed.","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:10:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fc442b64-1b5d-bebb-c486-f431b154f3db","last_modified":1480349196622},{"guid":"/^({ebd898f8-fcf6-4694-bc3b-eabc7271eeb1}|{46008e0d-47ac-4daa-a02a-5eb69044431a}|{213c8ed6-1d78-4d8f-8729-25006aa86a76}|{fa23121f-ee7c-4bd8-8c06-123d087282c5}|{19803860-b306-423c-bbb5-f60a7d82cde5})$/","prefs":[],"schema":1480349193877,"blockID":"i622","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947482","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is known to change user settings without their consent, is distributed under multiple add-on IDs, and is also correlated with reports of tab functions being broken in Firefox, in violation of the Add-on Guidelines.","name":"WiseConvert","created":"2014-06-18T13:48:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ffd184fa-aa8f-8a75-ff00-ce285dec5b22","last_modified":1480349196597},{"guid":"/^({fa95f577-07cb-4470-ac90-e843f5f83c52}|ffxtlbr@speedial\\.com)$/","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i696","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1031115","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using these add-ons can enable them in the Add-ons Manager.","why":"These add-ons are silently installed and change homepage and search defaults without user consent, in violation of the Add-on Guidelines. They are also distributed under more than one add-on ID.","name":"Speedial","created":"2014-08-21T13:55:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"130c7419-f727-a2fb-3891-627bc69a43bb","last_modified":1480349196565},{"guid":"pennerdu@faceobooks.ws","prefs":[],"schema":1480349193877,"blockID":"i442","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=904050","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Console Video (malware)","created":"2013-08-13T14:00:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb83e48e-a780-9d06-132c-9ecc65b43674","last_modified":1480349196541},{"guid":"anttoolbar@ant.com","prefs":[],"schema":1480349193877,"blockID":"i88","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=748269","who":"All Firefox users who have installed version 2.4.6.4 of the Ant Video Downloader and Player add-on.","why":"Version 2.4.6.4 of the Ant Video Downloader and Player add-on is causing a very high number of crashes in Firefox. There's an updated version 2.4.6.5 that doesn't have this problem. All users are recommended to update as soon as possible.","name":"Ant Video Downloader and Player","created":"2012-05-01T10:32:11Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.4.6.4","minVersion":"2.4.6.4","targetApplication":[]}],"id":"9eef435b-39d4-2b73-0810-44b0d3ff52ad","last_modified":1480349196509},{"guid":"{E90FA778-C2B7-41D0-9FA9-3FEC1CA54D66}","prefs":[],"schema":1480349193877,"blockID":"i446","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=788838","who":"All Firefox users who have this add-on installed. The add-on can be enabled again in the Add-ons Manager.","why":"This add-on is installed silently, in violation of our Add-on Guidelines.","name":"YouTube to MP3 Converter","created":"2013-09-06T15:59:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"83eb6337-a3b6-84e4-e76c-ee9200b80796","last_modified":1480349196471},{"guid":"{ad7ce998-a77b-4062-9ffb-1d0b7cb23183}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i804","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda Search Addon","created":"2014-12-15T10:53:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"633f9999-c81e-bd7a-e756-de7d34feb39d","last_modified":1480349196438},{"guid":"{52b0f3db-f988-4788-b9dc-861d016f4487}","prefs":[],"schema":1480349193877,"blockID":"i584","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974104","who":"All Firefox users who have these add-ons installed. If you wish to continue using these add-ons, you can enable them in the Add-ons Manager.","why":"Versions of this add-on are silently installed by the Free Driver Scout installer, in violation of our Add-on Guidelines.","name":"Web Check (Free Driver Scout bundle)","created":"2014-05-22T11:07:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.1.9999999","minVersion":"0","targetApplication":[]}],"id":"cba0ac44-90f9-eabb-60b0-8da2b645e067","last_modified":1480349196363},{"guid":"dodatek@flash2.pl","prefs":[],"schema":1480349193877,"blockID":"i1279","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"Any user with version 1.3 or newer of this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja Flash WORK addon","created":"2016-10-27T15:52:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"1.3","targetApplication":[]}],"id":"2dab5211-f9ec-a1bf-c617-6f94f28b5ee1","last_modified":1480349196331},{"guid":"{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}","prefs":[],"schema":1480349193877,"blockID":"i440","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=903647","who":"All Firefox users who have this add-on installed.","why":"This add-on is installed silently and doesn't follow many other of the Add-on Guidelines. If you want to continue using this add-on, you can enable it in the Add-ons Manager.","name":"GlitterFun","created":"2013-08-09T16:26:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3f77f3c-b1d6-3b29-730a-846007b9cb16","last_modified":1480349196294},{"guid":"xivars@aol.com","prefs":[],"schema":1480349193877,"blockID":"i501","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946420","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Video Plugin Facebook (malware)","created":"2013-12-04T15:34:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3303d201-7006-3c0d-5fd5-45503e2e690c","last_modified":1480349196247},{"guid":"2bbadf1f-a5af-499f-9642-9942fcdb7c76@f05a14cc-8842-4eee-be17-744677a917ed.com","prefs":[],"schema":1480349193877,"blockID":"i700","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1052599","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is widely considered malware and is apparently installed silently into users' systems, in violation of the Add-on Guidelines.","name":"PIX Image Viewer","created":"2014-08-21T16:15:16Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1b72889b-90e6-ea58-4fe8-d48257df7d8b","last_modified":1480349196212},{"guid":"/^[0-9a-f]+@[0-9a-f]+\\.info/","prefs":[],"schema":1480349193877,"blockID":"i256","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have installed any of these add-ons.","why":"The set of extensions labeled as Codec, Codec-M, Codec-C and other names are malware being distributed as genuine add-ons.\r\n\r\nIf you think an add-on you installed was incorrectly blocked and the block dialog pointed you to this page, please comment on this blog post.","name":"Codec extensions (malware)","created":"2013-01-22T12:16:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0c654540-00f2-0ad4-c9be-7ca2ace5341e","last_modified":1480349196184},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i600","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:16:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.5.*","minVersion":"3.15.5","targetApplication":[]}],"id":"51c4ab3b-9ad3-c5c3-98c8-a220025fc5a3","last_modified":1480349196158},{"guid":"{729c9605-0626-4792-9584-4cbe65b243e6}","prefs":[],"schema":1480349193877,"blockID":"i788","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Browser Ext Assistance","created":"2014-11-20T10:07:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3c588238-2501-6a53-65ea-5c8ff0f3e51d","last_modified":1480349196123},{"guid":"unblocker20__web@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1213","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 2.0","created":"2016-05-09T17:28:18Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"de305335-e9f3-f410-cf5c-f88b7ad4b088","last_modified":1480349196088},{"guid":"webbooster@iminent.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i630","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866943","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using them can enable them in the Add-ons Manager.","why":"These add-ons have been silently installed repeatedly, and change settings without user consent, in violation of the Add-on Guidelines.","name":"Iminent Minibar","created":"2014-06-26T15:49:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d894ea79-8215-7a0c-b0e9-be328c3afceb","last_modified":1480349196032},{"guid":"jid1-uabu5A9hduqzCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1016","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208051","who":"All users who have this add-on installed.","why":"This add-on is injecting unwanted and unexpected advertisements into all web pages, and masking this behavior as ad-blocking in its code.","name":"SpeedFox (malware)","created":"2015-09-24T09:49:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"31397419-3dfa-9db3-f1aa-e812d4220669","last_modified":1480349196001},{"guid":"/^firefox@(jumpflip|webconnect|browsesmart|mybuzzsearch|outobox|greygray|lemurleap|divapton|secretsauce|batbrowse|whilokii|linkswift|qualitink|browsefox|kozaka|diamondata|glindorus|saltarsmart|bizzybolt|websparkle)\\.(com?|net|org|info|biz)$/","prefs":[],"schema":1480349193877,"blockID":"i548","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937405","who":"All Firefox users who have one or more of these add-ons installed. If you wish to continue using any of these add-ons, they can be enabled in the Add-ons Manager.","why":"A large amount of add-ons developed by Yontoo are known to be silently installed and otherwise violate the Add-on Guidelines.","name":"Yontoo add-ons","created":"2014-01-30T15:06:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bfaf3510-397e-48e6-cc4f-74202aaaed54","last_modified":1480349195955},{"guid":"firefox@bandoo.com","prefs":[],"schema":1480349193877,"blockID":"i23","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=629634","who":"Users of Bandoo version 5.0 for Firefox 3.6 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"Bandoo","created":"2011-03-01T23:30:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.0","minVersion":"5.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"bd487cf4-3f6a-f956-a6e9-842ac8deeac5","last_modified":1480349195915},{"guid":"5nc3QHFgcb@r06Ws9gvNNVRfH.com","prefs":[],"schema":1480349193877,"blockID":"i372","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=875752","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware pretending to be the Flash Player plugin.","name":"Flash Player 11 (malware)","created":"2013-06-18T13:23:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dc71fcf5-fae4-5a5f-6455-ca7bbe4202db","last_modified":1480349195887},{"guid":"/^(7tG@zEb\\.net|ru@gfK0J\\.edu)$/","prefs":[],"schema":1480349193877,"blockID":"i854","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=952255","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"youtubeadblocker (malware)","created":"2015-02-09T15:41:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cfe42207-67a9-9b88-f80c-994e6bdd0c55","last_modified":1480349195851},{"guid":"{a7aae4f0-bc2e-a0dd-fb8d-68ce32c9261f}","prefs":[],"schema":1480349193877,"blockID":"i378","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=865090","who":"All Firefox users who have installed this add-on.","why":"This extension is malware that hijacks Facebook accounts for malicious purposes.","name":"Myanmar Extension for Facebook (malware)","created":"2013-06-18T15:58:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"30ecd9b9-4023-d9ef-812d-f1a75bb189b0","last_modified":1480349195823},{"guid":"a88a77ahjjfjakckmmabsy278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1034","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211171","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Fast Unlock (malware)","created":"2015-10-05T16:28:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f801f112-3e8f-770f-10db-384349a36026","last_modified":1480349195798},{"guid":"crossriderapp5060@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i228","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=810016","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and it overrides user preferences and inserts advertisements in web content.","name":"Savings Sidekick","created":"2012-11-29T16:31:13Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a37f76ac-7b77-b5a3-bac8-addaacf34bae","last_modified":1480349195769},{"guid":"/^(saamazon@mybrowserbar\\.com)|(saebay@mybrowserbar\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i672","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011337","who":"All Firefox users who have these add-ons installed. Users wishing to continue using these add-ons can enable them in the Add-ons Manager.","why":"These add-ons are being silently installed, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-07-22T15:13:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e072a461-ee5a-c83d-8d4e-5686eb585a15","last_modified":1480349195347},{"guid":"{b99c8534-7800-48fa-bd71-519a46cdc7e1}","prefs":[],"schema":1480349193877,"blockID":"i596","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011325","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, in violation with our Add-on Guidelines.","name":"BrowseMark","created":"2014-06-12T13:19:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f411bb0f-7c82-9061-4a80-cabc8ff45beb","last_modified":1480349195319},{"guid":"/^({94d62e35-4b43-494c-bf52-ba5935df36ef}|firefox@advanceelite\\.com|{bb7b7a60-f574-47c2-8a0b-4c56f2da9802})$/","prefs":[],"schema":1480349193877,"blockID":"i856","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1130323","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"AdvanceElite (malware)","created":"2015-02-09T15:51:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3d52650-d3e2-4cef-71f7-e6188f56fe4d","last_modified":1480349195286},{"guid":"{458fb825-2370-4973-bf66-9d7142141847}","prefs":["app.update.auto","app.update.enabled","app.update.interval","app.update.url"],"schema":1480349193877,"blockID":"i1024","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1209588","who":"All users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on hides itself in the Add-ons Manager, interrupts the Firefox update process, and reportedly causes other problems to users, in violation of the Add-on Guidelines.","name":"Web Shield","created":"2015-09-29T09:25:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32c5baa7-d547-eaab-302d-b873c83bfe2d","last_modified":1480349195258},{"guid":"{f2456568-e603-43db-8838-ffa7c4a685c7}","prefs":[],"schema":1480349193877,"blockID":"i778","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Sup-SW","created":"2014-11-07T13:53:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"93568fa2-0cb7-4e1d-e893-d7261e81547c","last_modified":1480349195215},{"guid":"{77BEC163-D389-42c1-91A4-C758846296A5}","prefs":[],"schema":1480349193877,"blockID":"i566","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=964594","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-on Manager.","why":"This add-on is silently installed into Firefox, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-03-05T13:20:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"080edbac-25d6-e608-abdd-feb1ce7a9a77","last_modified":1480349195185},{"guid":"helper@vidscrab.com","prefs":[],"schema":1480349193877,"blockID":"i1077","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1231010","who":"All Firefox users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on injects remote scripts and injects unwanted content into web pages.","name":"YouTube Video Downloader (from AddonCrop)","created":"2016-01-14T14:32:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"36b2e1e0-5fda-bde3-db55-dfcbe24dfd04","last_modified":1480349195157},{"guid":"/^ext@WebexpEnhancedV1alpha[0-9]+\\.net$/","prefs":[],"schema":1480349193877,"blockID":"i535","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=952717","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is generally unwanted by users and uses multiple random IDs in violation of the Add-on Guidelines.","name":"Webexp Enhanced","created":"2014-01-09T11:22:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c7d6a30d-f3ee-40fb-5256-138dd4593a61","last_modified":1480349195123},{"guid":"jid1-XLjasWL55iEE1Q@jetpack","prefs":[],"schema":1480349193877,"blockID":"i578","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1002037","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that presents itself as \"Flash Player\" but is really injecting unwanted content into Facebook pages.","name":"Flash Player (malware)","created":"2014-04-28T16:25:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1e75b2f0-02fc-77a4-ad2f-52a4caff1a71","last_modified":1480349195058},{"guid":"{a3a5c777-f583-4fef-9380-ab4add1bc2a8}","prefs":[],"schema":1480349193877,"blockID":"i142","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=792132","who":"Todos los usuarios de Firefox que instalaron la versi\u00f3n 4.2 del complemento Cuevana Stream.\r\n\r\nAll Firefox users who have installed version 4.2 of the Cuevana Stream add-on.","why":"Espa\u00f1ol\r\nUna versi\u00f3n maliciosa del complemento Cuevana Stream (4.2) fue colocada en el sitio Cuevana y distribuida a muchos usuarios del sitio. Esta versi\u00f3n recopila informaci\u00f3n de formularios web y los env\u00eda a una direcci\u00f3n remota con fines maliciosos. Se le recomienda a todos los usuarios que instalaron esta versi\u00f3n que cambien sus contrase\u00f1as inmediatamente, y que se actualicen a la nueva versi\u00f3n segura, que es la 4.3.\r\n\r\nEnglish\r\nA malicious version of the Cuevana Stream add-on (4.2) was uploaded to the Cuevana website and distributed to many of its users. This version takes form data and sends it to a remote location with malicious intent. It is recommended that all users who installed this version to update their passwords immediately, and update to the new safe version, version 4.3.\r\n\r\n","name":"Cuevana Stream (malicious version)","created":"2012-09-18T13:37:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"4.2","minVersion":"4.2","targetApplication":[]}],"id":"91e551b9-7e94-60e2-f1bd-52f25844ab16","last_modified":1480349195007},{"guid":"{34712C68-7391-4c47-94F3-8F88D49AD632}","prefs":[],"schema":1480349193877,"blockID":"i922","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:27:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"dd350efb-34ac-2bb5-5afd-eed722dbb916","last_modified":1480349194976},{"guid":"PDVDZDW52397720@XDDWJXW57740856.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i846","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128320","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and attempts to change user settings like the home page and default search, in violation of the Add-on Guidelines.","name":"Ge-Force","created":"2015-02-06T15:03:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c33e950c-c977-ed89-c86a-3be8c4be1967","last_modified":1480349194949},{"guid":"{977f3b97-5461-4346-92c8-a14c749b77c9}","prefs":[],"schema":1480349193877,"blockID":"i69","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=729356","who":"All Firefox users who have this add-on installed.","why":"This add-on adds apps to users' accounts, with full access permissions, and sends spam posts using these apps, all without any consent from users.","name":"Zuperface+","created":"2012-02-22T16:41:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f105bdc7-7ebd-587c-6344-1533249f50b3","last_modified":1480349194919},{"guid":"discoverypro@discoverypro.com","prefs":[],"schema":1480349193877,"blockID":"i582","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1004231","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enabled it in the Add-ons Manager.","why":"This add-on is silently installed by the CNET installer for MP3 Rocket and probably other software packages. This is in violation of the Add-on Guidelines.","name":"Website Discovery Pro","created":"2014-04-30T16:10:03Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"34eab242-6fbc-a459-a89e-0dc1a0b8355d","last_modified":1480349194878},{"guid":"jid1-bKSXgRwy1UQeRA@jetpack","prefs":[],"schema":1480349193877,"blockID":"i680","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=979856","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into user's systems, in violation of the Add-on Guidelines.","name":"Trusted Shopper","created":"2014-08-01T16:34:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f701b790-b266-c69d-0fba-f2d189cb0f34","last_modified":1480349194851},{"guid":"bcVX5@nQm9l.org","prefs":[],"schema":1480349193877,"blockID":"i848","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128266","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"boomdeal","created":"2015-02-09T15:21:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8d6d4e1-b9e6-07f5-2b49-192106a45d82","last_modified":1480349194799},{"guid":"aytac@abc.com","prefs":[],"schema":1480349193877,"blockID":"i504","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947341","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-06T12:07:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bfaf8298-dd69-165c-e1ed-ad55584abd18","last_modified":1480349194724},{"guid":"Adobe@flash.com","prefs":[],"schema":1480349193877,"blockID":"i136","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=790100","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware posing as a legitimate Adobe product.","name":"Adobe Flash (malware)","created":"2012-09-10T16:09:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"47ac744e-3176-5cb6-1d02-b460e0c7ada0","last_modified":1480349194647},{"guid":"{515b2424-5911-40bd-8a2c-bdb20286d8f5}","prefs":[],"schema":1480349193877,"blockID":"i491","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=940753","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"Connect DLC","created":"2013-11-29T14:52:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d658443-b34a-67ad-934e-cbf7cd407460","last_modified":1480349194580},{"guid":"/^({3f3cddf8-f74d-430c-bd19-d2c9147aed3d}|{515b2424-5911-40bd-8a2c-bdb20286d8f5}|{17464f93-137e-4646-a0c6-0dc13faf0113}|{d1b5aad5-d1ae-4b20-88b1-feeaeb4c1ebc}|{aad50c91-b136-49d9-8b30-0e8d3ead63d0})$/","prefs":[],"schema":1480349193877,"blockID":"i516","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947478","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and being distributed under multiple add-on IDs.","name":"Connect DLC","created":"2013-12-20T12:38:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"96f8e157-8b8b-8e2e-76cd-6850599b4370","last_modified":1480349194521},{"guid":"wxtui502n2xce9j@no14","prefs":[],"schema":1480349193877,"blockID":"i1012","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1206157","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Video fix (malware)","created":"2015-09-21T13:04:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"246798ac-25fa-f4a4-258c-a71f9f6ae091","last_modified":1480349194463},{"guid":"flashX@adobe.com","prefs":[],"schema":1480349193877,"blockID":"i168","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=807052","who":"All Firefox users who have this add-on installed.","why":"This is an exploit proof-of-concept created for a conference presentation, which will probably be copied and modified for malicious purposes. \r\n","name":"Zombie Browser Pack","created":"2012-10-30T12:07:41Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d7c69812-801c-8d8e-12cb-c5171bdc48a1","last_modified":1480349194428},{"guid":"/^(ff\\-)?dodate(kKKK|XkKKK|k|kk|kkx|kR)@(firefox|flash(1)?)\\.pl|dode(ee)?k@firefoxnet\\.pl|(addon|1)@upsolutions\\.pl$/","prefs":[],"schema":1480349193877,"blockID":"i1278","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"Any user with a version of this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja dodatku Flash Add-on","created":"2016-10-27T10:52:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"389aec65-a15d-8276-c7a8-691ac283c9f1","last_modified":1480349194386},{"guid":"tmbepff@trendmicro.com","prefs":[],"schema":1480349193877,"blockID":"i1223","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1275245","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"Add-on is causing a high-frequency crash in Firefox.","name":"Trend Micro BEP 9.2 to 9.2.0.1023","created":"2016-05-30T17:07:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.2.0.1023","minVersion":"9.2","targetApplication":[]}],"id":"46f75b67-2675-bdde-be93-7ea03475d405","last_modified":1480349194331},{"guid":"{4889ddce-7a83-45e6-afc9-1e4f1149fff4}","prefs":[],"schema":1480343836083,"blockID":"i840","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128327","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"Cyti Web (malware)","created":"2015-02-06T14:30:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be600f35-0633-29f3-c571-819e19d85db9","last_modified":1480349193867},{"guid":"{55dce8ba-9dec-4013-937e-adbf9317d990","prefs":[],"schema":1480343836083,"blockID":"i690","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1048647","who":"All Firefox users. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed in users' systems, in violation of the Add-on Guidelines.","name":"Deal Keeper","created":"2014-08-12T16:23:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"512b0d40-a10a-5ddc-963b-b9c487eb1422","last_modified":1480349193833},{"guid":"/^new@kuot\\.pro|{13ec6687-0b15-4f01-a5a0-7a891c18e4ee}|rebeccahoppkins(ty(tr)?)?@gmail\\.com|{501815af-725e-45be-b0f2-8f36f5617afc}|{9bdb5f1f-b1e1-4a75-be31-bdcaace20a99}|{e9d93e1d-792f-4f95-b738-7adb0e853b7b}|dojadewaskurwa@gmail\\.com$/","prefs":[],"schema":1480343836083,"blockID":"i1414","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"All users who have this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja dodatku Flash (malware)","created":"2016-10-28T18:06:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5cebc983-bc88-d5f8-6807-bd1cbfcd82fd","last_modified":1480349193798},{"guid":"/^pink@.*\\.info$/","prefs":[],"schema":1480343836083,"blockID":"i238","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806543","who":"All Firefox users (Firefox 19 and above) who have any of these add-ons installed.","why":"This is a set of malicious add-ons that affect many users and are installed without their consent.","name":"Pink add-ons (malware)","created":"2012-12-07T13:46:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"18.0"}]}],"id":"0d964264-8bd6-b78d-3c6c-92046c7dc8d0","last_modified":1480349193764},{"guid":"{58d2a791-6199-482f-a9aa-9b725ec61362}","prefs":[],"schema":1480343836083,"blockID":"i746","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963787","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Start Page","created":"2014-10-17T16:01:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8ebbc7d0-635c-b74a-de9f-16eb5837b36a","last_modified":1480349193730},{"guid":"{94cd2cc3-083f-49ba-a218-4cda4b4829fd}","prefs":[],"schema":1480343836083,"blockID":"i590","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1013678","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' profiles, in violation of the Add-on Guidelines.","name":"Value Apps","created":"2014-06-03T16:12:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"556b8d4d-d6c2-199d-9f33-8eccca07e8e7","last_modified":1480349193649},{"guid":"contentarget@maildrop.cc","prefs":[],"schema":1480343836083,"blockID":"i818","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119971","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts.","name":"Astro Play (malware)","created":"2015-01-12T09:29:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"440e9923-027a-6089-e036-2f78937dc193","last_modified":1480349193622},{"guid":"unblocker30__web@unblocker.yt","prefs":[],"schema":1480343836083,"blockID":"i1228","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 3.0","created":"2016-06-01T15:17:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2d83e640-ef9d-f260-f5a3-a1a5c8390bfc","last_modified":1480349193595},{"guid":"noOpus@outlook.com","prefs":[],"schema":1480343836083,"blockID":"i816","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119659","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent and performs unwanted operations.","name":"Full Screen (malware)","created":"2015-01-09T12:52:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b64d7cef-8b6c-2575-16bc-732fca7db377","last_modified":1480349193537},{"guid":"{c95a4e8e-816d-4655-8c79-d736da1adb6d}","prefs":[],"schema":1480343836083,"blockID":"i433","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844945","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield","created":"2013-08-09T11:25:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b3168278-a8ae-4882-7f26-355bc362bed0","last_modified":1480349193510},{"guid":"{9802047e-5a84-4da3-b103-c55995d147d1}","prefs":[],"schema":1480343836083,"blockID":"i722","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Web Finder Pro","created":"2014-10-07T12:58:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"50097c29-26b1-bf45-ffe1-83da217eb127","last_modified":1480349193482},{"guid":"/^({bf9194c2-b86d-4ebc-9b53-1c08b6ff779e}|{61a83e16-7198-49c6-8874-3e4e8faeb4f3}|{f0af464e-5167-45cf-9cf0-66b396d1918c}|{5d9968c3-101c-4944-ba71-72d77393322d}|{01e86e69-a2f8-48a0-b068-83869bdba3d0})$/","prefs":[],"schema":1480343836083,"blockID":"i515","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947473","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by using multiple add-on IDs and making unwanted settings changes.","name":"VisualBee Toolbar","created":"2013-12-20T12:26:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"029fa6f9-2351-40b7-5443-9a66e057f199","last_modified":1480349193449},{"guid":"/^({d50bfa5f-291d-48a8-909c-5f1a77b31948}|{d54bc985-6e7b-46cd-ad72-a4a266ad879e}|{d89e5de3-5543-4363-b320-a98cf150f86a}|{f3465017-6f51-4980-84a5-7bee2f961eba}|{fae25f38-ff55-46ea-888f-03b49aaf8812})$/","prefs":[],"schema":1480343836083,"blockID":"i1137","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hides itself from view and disables various security features in Firefox.","name":"Watcher (malware)","created":"2016-03-04T17:56:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"252e18d0-85bc-7bb3-6197-5f126424c9b3","last_modified":1480349193419},{"guid":"ffxtlbr@claro.com","prefs":[],"schema":1480343836083,"blockID":"i218","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=816762","who":"All Firefox users who have installed this add-on.","why":"The Claro Toolbar is side-installed with other software, unexpectedly changing users' settings and then making it impossible for these settings to be reverted by users.","name":"Claro Toolbar","created":"2012-11-29T16:07:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e017a3b2-9b37-b8a0-21b0-bc412ae8a7f4","last_modified":1480349193385},{"guid":"/^(.*@(unblocker\\.yt|sparpilot\\.com))|(axtara@axtara\\.com)$/","prefs":[],"schema":1480343836083,"blockID":"i1229","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"These add-ons are copies of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker (various)","created":"2016-06-03T15:28:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c677cc5d-5b1e-8aa2-5cea-5a8dddce2ecf","last_modified":1480349193344},{"guid":"/^(j003-lqgrmgpcekslhg|SupraSavings|j003-dkqonnnthqjnkq|j003-kaggrpmirxjpzh)@jetpack$/","prefs":[],"schema":1480343836083,"blockID":"i692","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1048656","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed in users' systems, in violation of the Add-on Guidelines.","name":"SupraSavings","created":"2014-08-12T16:27:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b0d30256-4581-1489-c241-d2e85b6c38f4","last_modified":1480349193295},{"guid":"helperbar@helperbar.com","prefs":[],"schema":1480343836083,"blockID":"i258","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=817786","who":"All Firefox users who have this add-on installed. This only applies to version 1.0 of Snap.do. Version 1.1 fixed all the issues for which this block was created.","why":"This extension violates a number of our Add-on Guidelines, particularly on installation and settings handling. It also causes some stability problems in Firefox due to the way the toolbar is handled.\r\n\r\nUsers who wish to keep the add-on enabled can enable it again in the Add-ons Manager.","name":"Snap.do","created":"2013-01-28T13:52:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0","minVersion":"0","targetApplication":[]}],"id":"f1ede5b8-7757-5ec5-d8ed-1a01889154aa","last_modified":1480349193254},{"guid":"/^((support2_en@adobe14\\.com)|(XN4Xgjw7n4@yUWgc\\.com)|(C7yFVpIP@WeolS3acxgS\\.com)|(Kbeu4h0z@yNb7QAz7jrYKiiTQ3\\.com)|(aWQzX@a6z4gWdPu8FF\\.com)|(CBSoqAJLYpCbjTP90@JoV0VMywCjsm75Y0toAd\\.com)|(zZ2jWZ1H22Jb5NdELHS@o0jQVWZkY1gx1\\.com))$/","prefs":[],"schema":1480343836083,"blockID":"i326","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=841791","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:49:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3142020b-8af9-1bac-60c5-ce5ad0ff3d42","last_modified":1480349193166},{"guid":"newmoz@facebook.com","prefs":[],"schema":1480343836083,"blockID":"i576","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=997986","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook user accounts and sends spam on the user's behalf.","name":"Facebook Service Pack (malware)","created":"2014-04-22T14:34:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d85798d3-9b87-5dd9-ace2-64914b93df77","last_modified":1480349193114},{"guid":"flvto@hotger.com","prefs":[],"schema":1480343836083,"blockID":"i1211","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1270175","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on reports every visited URL to a third party without disclosing it to the user.","name":"YouTube to MP3 Button","created":"2016-05-04T16:26:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a14d355f-719f-3b97-506c-083cc97cebaa","last_modified":1480349193088},{"guid":"{0F827075-B026-42F3-885D-98981EE7B1AE}","prefs":[],"schema":1480343836083,"blockID":"i334","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=862272","who":"All Firefox users who have this extension installed.","why":"This extension is malicious and is installed under false pretenses, causing problems for many Firefox users. Note that this is not the same BrowserProtect extension that is listed on our add-ons site. That one is safe to use.","name":"Browser Protect / bProtector (malware)","created":"2013-04-16T13:25:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aad4545f-8f9d-dd53-2aa8-e8945cad6185","last_modified":1480349192987}]} \ No newline at end of file +{"data":[{"guid":"{38363d75-6591-4e8b-bf01-0270623d1b6c}","prefs":[],"schema":1526326889114,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1461625","why":"This add-on contains abusive functionality.","name":"Photobucket Hotlink Fix"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"0f0764d5-a290-428b-a5b2-3767e1d72c71","last_modified":1526381862851},{"guid":"@vkmad","prefs":[],"schema":1526154098016,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1461410","why":"This add-on includes malicious functionality.","name":"VK Universal Downloader (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"cbfa5303-c1bf-49c8-87d8-259738a20064","last_modified":1526322954850},{"guid":"/^(({41c14ab8-9958-44bf-b74e-af54c1f169a6})|({78054cb2-e3e8-4070-a8ad-3fd69c8e4707})|({0089b179-8f3d-44d9-bb18-582843b0757a})|({f44ddcb4-4cc0-4866-92fa-eefda60c6720})|({1893d673-7953-4870-8069-baac49ce3335})|({fb28cac0-c2aa-4e0c-a614-cf3641196237})|({d7dee150-da14-45ba-afca-02c7a79ad805})|(RandomNameTest@RandomNameTest\\.com )|(corpsearchengine@mail\\.ru)|(support@work\\.org))$/","prefs":[],"schema":1525377099963,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1458330","why":"These are malicious add-ons that inject remote scripts and use deceptive names.","name":"\"Table\" add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3a123214-b4b6-410c-a061-bbaf0d168d31","last_modified":1525377135149},{"guid":"/((@extcorp\\.[a-z]+)|(@brcorporation\\.com)|(@brmodcorp\\.com)|(@teset\\.com)|(@modext\\.tech)|(@ext?mod\\.net)|(@browcorporation\\.org)|(@omegacorporation\\.org)|(@browmodule\\.com)|(@corpext\\.net)|({6b50ddac-f5e0-4d9e-945b-e4165bfea5d6})|({fab6484f-b8a7-4ba9-a041-0f948518b80c})|({b797035a-7f29-4ff5-bd19-77f1b5e464b1})|({0f612416-5c5a-4ec8-b482-eb546af9cac4}))$/","prefs":[],"schema":1525290095999,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1458330","why":"These are malicious add-ons that inject remote scripts and use deceptive names.","name":"\"Table\" add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3ab9f100-e253-4080-b3e5-652f842ddb7a","last_modified":1525377099954},{"guid":"/^({b99ae7b1-aabb-4674-ba8f-14ed32d04e76})|({dfa77d38-f67b-4c41-80d5-96470d804d09})$/","prefs":[],"schema":1524146566650,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1455291","why":"These add-ons claim to be the flash plugin.","name":"Flash Plugin (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"96b137e6-8cb5-44d6-9a34-4a4a76fb5e38","last_modified":1524147337556},{"guid":"/^({6ecb9f49-90f0-43a1-8f8a-e809ea4f732b})|(@googledashboard)|(@smashdashboard)|(@smash_tv)|(@smash_mov)|(@smashmovs)|(@smashtvs)|(@FirefoxUpdate)|({92b9e511-ac81-4d47-9b8f-f92dc872447e})|({3c841114-da8c-44ea-8303-78264edfe60b})|({116a0754-20eb-4fe5-bd35-575867a0b89e})|({6e6ff0fd-4ae4-49ae-ac0c-e2527e12359b})|({f992ac88-79d3-4960-870e-92c342ed3491})|({6ecb9f49-90f0-43a1-8f8a-e809ea4f732b})|({a512297e-4d3a-468c-bd1a-f77bd093f925})|({08c28c16-9fb6-4b32-9868-db37c1668f94})|({b4ab1a1d-e137-4c59-94d5-4f509358a81d})|({feedf4f8-08c1-451f-a717-f08233a64ec9})$/","prefs":[],"schema":1524139371832,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1454691","why":"This malware prevents itself from getting uninstalled ","name":"Malware"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"feb2d0d7-1b76-4dba-bf84-42873a92af5f","last_modified":1524141477640},{"guid":"{872f20ea-196e-4d11-8835-1cc4c877b1b8}","prefs":[],"schema":1523734896380,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1454413","why":"Extension claims to be Flash Player","name":"Flash Player (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"1e5f5cb2-346c-422a-9aaa-29d8760949d2","last_modified":1523897202689},{"guid":"/(__TEMPLATE__APPLICATION__@ruta-mapa\\.com)|(application-3@findizer\\.fr)|(application2@allo-pages\\.fr)|(application2@bilan-imc\\.fr)|(application2@lettres\\.net)|(application2@search-maps-finder\\.com)|(application-imcpeso@imc-peso\\.com)|(application-meuimc@meu-imc\\.com)|(application-us2@factorlove)|(application-us@misterdirections)|(application-us@yummmi\\.es)|(application@amiouze\\.fr)|(application@astrolignes\\.com)|(application@blotyn\\.com)|(application@bmi-result\\.com)|(application@bmi-tw\\.com)|(application@calcolo-bmi\\.com)|(application@cartes-itineraires\\.com)|(application@convertisseur\\.pro)|(application@de-findizer\\.fr)|(application@de-super-rezepte\\.com)|(application@dermabeauty\\.fr)|(application@dev\\.squel\\.v2)|(application@eu-my-drivingdirections\\.com)|(application@fr-allo-pages\\.fr)|(application@fr-catizz\\.com)|(application@fr-mr-traduction\\.com)|(application@good-recettes\\.com)|(application@horaires\\.voyage)|(application@imc-calcular\\.com)|(application@imc-peso\\.com)|(application@it-mio-percorso\\.com)|(application@iti-maps\\.fr)|(application@itineraire\\.info)|(application@lbc-search\\.com)|(application@les-pages\\.com)|(application@lovincalculator\\.com)|(application@lovintest\\.com)|(application@masowe\\.com)|(application@matchs\\.direct)|(application@mein-bmi\\.com)|(application@mes-resultats\\.com)|(application@mestaf\\.com)|(application@meu-imc\\.com)|(application@mon-calcul-imc\\.fr)|(application@mon-juste-poids\\.com)|(application@mon-trajet\\.com)|(application@my-drivingdirections\\.com)|(application@people-show\\.com)|(application@plans-reduc\\.fr)|(application@point-meteo\\.fr)|(application@poulixo\\.com)|(application@quipage\\.fr)|(application@quizdeamor\\.com)|(application@quizdoamor\\.com)|(application@quotient-retraite\\.fr)|(application@recettes\\.net)|(application@routenplaner-karten\\.com)|(application@ruta-mapa\\.com)|(application@satellite\\.dev\\.squel\\.v2)|(application@search-bilan-imc\\.fr)|(application@search-maps-finder\\.com)|(application@slimness\\.fr)|(application@start-bmi\\.com)|(application@tests-moi\\.com)|(application@tousmesjeux\\.fr)|(application@toutlannuaire\\.fr)|(application@tuto-diy\\.com)|(application@ubersetzung-app\\.com)|(application@uk-cookyummy\\.com)|(application@uk-howlogin\\.me)|(application@uk-myloap\\.com)|(application@voyagevoyage\\.co)|(application@wikimot\\.fr)|(application@www\\.plans-reduc\\.fr)|(application@yummmi\\.es)|(application@yummmies\\.be)|(application@yummmies\\.ch)|(application@yummmies\\.fr)|(application@yummmies\\.lu)|(application@zikplay\\.fr)|(applicationY@search-maps-finder\\.com)|(cmesapps@findizer\\.fr)|(findizer-shopping@jetpack)|(\\{8aaebb36-1488-4022-b7ec-29b790d12c17\\})/","prefs":[],"schema":1523216496621,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1452648","why":"Those add-ons do not provide a real functionality for users, other than silently tracking browsing behavior.","name":"Tracking Add-ons (harmful)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"36f97298-8bef-4372-a548-eb829413bee9","last_modified":1523286321447},{"guid":"adbeaver@adbeaver.org","prefs":[],"schema":1521630548030,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1445031","why":"This add-on generates numerous errors when loading Facebook, caused by ad injection included in it. Users who want to continue using this add-on can enable it in the Add-ons Manager.","name":"AdBeaver"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0"}],"id":"baf7f735-d6b6-410a-8cc8-25c60f7c57e2","last_modified":1522103097333},{"guid":"{44685ba6-68b3-4895-879e-4efa29dfb578}","prefs":[],"schema":1521565140013,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1447042","why":"This add-on impersonates a Flash tool and runs remote code on users' systems.","name":"FF Flash Manager"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"547037f2-97ae-435a-863c-efd7532668cd","last_modified":1521630548023},{"guid":"/^.*extension.*@asdf\\.pl$/","prefs":[],"schema":1520451695869,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1444037","why":"These add-ons are using deceptive names and taking over Facebook accounts to post spam content.","name":"Facebook spammers"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3d55fab0-ec1a-4bca-84c9-3b74f5d01509","last_modified":1520527480321},{"guid":"/^(addon@fasterweb\\.com|\\{5f398d3f-25db-47f5-b422-aa2364ff6c0b\\}|addon@fasterp\\.com|addon@calculator)$/","prefs":[],"schema":1520338910918,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1443478","why":"These are malicious add-ons that use deceptive names and run remote scripts.","name":"FasterWeb add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"f58729ec-f93c-41d9-870d-dd9c9fd811b6","last_modified":1520358450708},{"guid":"{42baa93e-0cff-4289-b79e-6ae88df668c4}","prefs":[],"schema":1520336325565,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1443196","why":"The add-on claims to be \"Adobe Shockwave Flash Player\"","name":"Adobe Shockwave Flash Player (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"0cd723fe-d33d-43a0-b84f-7a3cad253212","last_modified":1520338780397},{"guid":"/{0c9970a2-6874-483b-a486-2296cfe251c2}|{01c9a4a4-06dd-426b-9500-2ea6fe841b88}|{1c981c7c-30e0-4ed2-955d-6b370e0a9d19}|{2aa275f8-fabc-4766-95b2-ecfc73db310b}|{2cac0be1-10a2-4a0d-b8c5-787837ea5955}|{2eb66f6c-94b3-44f5-9de2-22371236ec99}|{2f8aade6-8717-4277-b8b1-55172d364903}|{3c27c34f-8775-491a-a1c9-fcb15beb26d3}|{3f4dea3e-dbfc-428f-a88b-36908c459e20}|{3f4191fa-8f16-47d2-9414-36bfc9e0c2bf}|{4c140bc5-c2ad-41c3-a407-749473530904}|{05a21129-af2a-464c-809f-f2df4addf209}|{5da81d3d-5db1-432a-affc-4a2fe9a70749}|{5f4e63e4-351f-4a21-a8e5-e50dc72b5566}|{7c1df23b-1fd8-42b9-8752-71fff2b979de}|{7d5e24a1-7bef-4d09-a952-b9519ec00d20}|{7d932012-b4dd-42cc-8a78-b15ca82d0e61}|{7f8bc48d-1c7c-41a0-8534-54adc079338f}|{8a61507d-dc2f-4507-a9b7-7e33b8cbc31b}|{09c8fa16-4eec-4f78-b19d-9b24b1b57e1e}|{9ce2a636-0e49-4b8e-ad17-d0c156c963b0}|{11df9391-dba5-4fe2-bd48-37a9182b796d}|{23c65153-c21e-430a-a2dc-0793410a870d}|{36a4269e-4eef-4538-baea-9dafbf6a8e2f}|{37f8e483-c782-40ed-82e9-36f101b9e41f}|{63df223d-51cf-4f76-aad8-bbc94c895ed2}|{72c1ca96-c05d-46a7-bce1-c507ec3db4ea}|{76ce213c-8e57-4a14-b60a-67a5519bd7a7}|{79db6c96-d65a-4a64-a892-3d26bd02d2d9}|{81ac42f3-3d17-4cff-85af-8b7f89c8826b}|{83d38ac3-121b-4f28-bf9c-1220bd3c643b}|{86d98522-5d42-41d5-83c2-fc57f260a3d9}|{0111c475-01e6-42ea-a9b4-27bed9eb6092}|{214cb48a-ce31-4e48-82cf-a55061f1b766}|{216e0bcc-8a23-4069-8b63-d9528b437258}|{226b0fe6-f80f-48f1-9d8d-0b7a1a04e537}|{302ef84b-2feb-460e-85ca-f5397a77aa6a}|{408a506b-2336-4671-a490-83a1094b4097}|{419be4e9-c981-478e-baa0-937cf1eea1e8}|{0432b92a-bfcf-41b9-b5f0-df9629feece1}|{449e185a-dd91-4f7b-a23a-bbf6c1ca9435}|{591d1b73-5eae-47f4-a41f-8081d58d49bf}|{869b5825-e344-4375-839b-085d3c09ab9f}|{919fed43-3961-48d9-b0ef-893054f4f6f1}|{01166e60-d740-440c-b640-6bf964504b3c}|{2134e327-8060-441c-ba68-b167b82ff5bc}|{02328ee7-a82b-4983-a5f7-d0fc353698f0}|{6072a2a8-f1bc-4c9c-b836-7ac53e3f51e4}|{28044ca8-8e90-435e-bc63-a757af2fb6be}|{28092fa3-9c52-4a41-996d-c43e249c5f08}|{31680d42-c80d-4f8a-86d3-cd4930620369}|{92111c8d-0850-4606-904a-783d273a2059}|{446122cd-cd92-4d0c-9426-4ee0d28f6dca}|{829827cd-03be-4fed-af96-dd5997806fb4}|{4479446e-40f3-48af-ab85-7e3bb4468227}|{9263519f-ca57-4178-b743-2553a40a4bf1}|{71639610-9cc3-47e0-86ed-d5b99eaa41d5}|{84406197-6d37-437c-8d82-ae624b857355}|{93017064-dfd4-425e-a700-353f332ede37}|{a0ab16af-3384-4dbe-8722-476ce3947873}|{a0c54bd8-7817-4a40-b657-6dc7d59bd961}|{a2de96bc-e77f-4805-92c0-95c9a2023c6a}|{a3fbc8be-dac2-4971-b76a-908464cfa0e0}|{a42e5d48-6175-49e3-9e40-0188cde9c5c6}|{a893296e-5f54-43f9-a849-f12dcdee2c98}|{ac296b47-7c03-486f-a1d6-c48b24419749}|{b26bf964-7aa6-44f4-a2a9-d55af4b4eec0}|{be981b5e-1d9d-40dc-bd4f-47a7a027611c}|{be37931c-af60-4337-8708-63889f36445d}|{bfd92dfd-b293-4828-90c1-66af2ac688e6}|{c5cf4d08-0a33-4aa3-a40d-d4911bcc1da7}|{c488a8f5-ea3d-408d-809e-44e82c06ad9d}|{c661c2dc-00f9-4dc1-a9f6-bb2b7e1a4f8d}|{cd28aa38-d2f1-45a3-96c3-6cfd4702ef51}|{cd89045b-2e06-46bb-9e34-48e8799e5ef2}|{cf9d96ff-5997-439a-b32b-98214c621eee}|{d14acee6-f32b-4aa3-a802-6616003fc6a8}|{d97223b8-44e5-46c7-8ab5-e1d8986daf44}|{ddae89bd-6793-45d8-8ec9-7f4fb7212378}|{de3b1909-d4da-45e9-8da5-7d36a30e2fc6}|{df09f268-3c92-49db-8c31-6a25a6643896}|{e5bc3951-c837-4c98-9643-3c113fc8cf5e}|{e9ccb1f2-a8ba-4346-b43b-0d5582bce414}|{e341ed12-a703-47fe-b8dd-5948c38070e4}|{e2139287-2b0d-4f54-b3b1-c9a06c597223}|{ed352072-ddf0-4cb4-9cb6-d8aa3741c2de}|{f0b809eb-be22-432f-b26f-b1cadd1755b9}|{f1bce8e4-9936-495b-bf48-52850c7250ab}|{f01c3add-dc6d-4f35-a498-6b4279aa2ffa}|{f9e1ad25-5961-4cc5-8d66-5496c438a125}|{f4262989-6de0-4604-918f-663b85fad605}|{fc0d55bd-3c50-4139-9409-7df7c1114a9d}/","prefs":[],"schema":1519766961483,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1439702","why":"This malicious add-on claims to be a Firefox \"helper\" or \"updater\" or similar.","name":"FF updater (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"48b14881-5f6b-4e48-afc5-3d9a7fae26a3","last_modified":1519826648080},{"guid":"{44e4b2cf-77ba-4f76-aca7-f3fcbc2dda2f} ","prefs":[],"schema":1519414957616,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1440821","why":"This is a malicious add-on that uses a deceptive name and runs remote code.","name":"AntiVirus for Firefox"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2447476f-043b-4d0b-9d3c-8e859c97d950","last_modified":1519429178266},{"guid":"{f3c31b34-862c-4bc8-a98f-910cc6314a86}","prefs":[],"schema":1519242096699,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1440736","why":"This is a malicious add-on that is masked as an official Adobe Updater and runs malicious code.","name":"Adobe Updater (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"adfd98ef-cebc-406b-b1e0-61bd4c71e4b1","last_modified":1519409417397},{"guid":"/^(\\{fd0c36fa-6a29-4246-810b-0bb4800019cb\\}|\\{b9c1e5bf-6585-4766-93fc-26313ac59999\\}|\\{3de25fff-25e8-40e9-9ad9-fdb3b38bb2f4\\})$/","prefs":[],"schema":1519069296530,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1439432","why":"These are malicious add-ons that are masked as an official Adobe Updater and run malicious code.","name":"Adobe Updater"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"4e28ba5c-af62-4e53-a7a1-d33334571cf8","last_modified":1519078890592},{"guid":"/^(\\{01c9a4a4-06dd-426b-9500-2ea6fe841b88\\}|{5e024309-042c-4b9d-a634-5d92cf9c7514\\}|{f4262989-6de0-4604-918f-663b85fad605\\}|{e341ed12-a703-47fe-b8dd-5948c38070e4\\}|{cd89045b-2e06-46bb-9e34-48e8799e5ef2\\}|{ac296b47-7c03-486f-a1d6-c48b24419749\\}|{5da81d3d-5db1-432a-affc-4a2fe9a70749\\}|{df09f268-3c92-49db-8c31-6a25a6643896\\}|{81ac42f3-3d17-4cff-85af-8b7f89c8826b\\}|{09c8fa16-4eec-4f78-b19d-9b24b1b57e1e\\}|{71639610-9cc3-47e0-86ed-d5b99eaa41d5\\}|{83d38ac3-121b-4f28-bf9c-1220bd3c643b\\}|{7f8bc48d-1c7c-41a0-8534-54adc079338f\\})$/","prefs":[],"schema":1518550894975,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1438028","why":"These are malicious add-ons that inject remote scripts into popular websites.","name":"Page Marker add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"cc5848e8-23d5-4655-b45c-dc239839b74e","last_modified":1518640450735},{"guid":"/^(https|youtube)@vietbacsecurity\\.com$/","prefs":[],"schema":1517909997354,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1435974","why":"These add-ons contain malicious functionality, violating the users privacy and security.","name":"HTTPS and Youtube downloader (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"646e2384-f894-41bf-b7fc-8879e0095109","last_modified":1517910100624},{"guid":"{ed352072-ddf0-4cb4-9cb6-d8aa3741c2de}","prefs":[],"schema":1517514097126,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1434893","why":"This is a malicious add-on that injects remote scripts into popular pages while pretending to do something else.","name":"Image previewer"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2104a522-bb2f-4b04-ad0d-b0c571644552","last_modified":1517577111194},{"guid":"/^(\\{0b24cf69-02b8-407d-83db-e7af04fc1f3e\\})|(\\{6feed48d-41d4-49b8-b7d6-ef78cc7a7cd7\\})| (\\{8a0699a0-09c3-4cf1-b38d-fec25441650c\\})$/","prefs":[],"schema":1517341295286,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1434759","why":"These add-ons use remote scripts to alter popular sites like Google or Amazon.","name":"Malicious remote script add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"32ffc62d-40c4-43ac-aa3f-7240978d0ad0","last_modified":1517439279474},{"guid":"/^({be5d0c88-571b-4d01-a27a-cc2d2b75868c})|({3908d078-e1db-40bf-9567-5845aa77b833})|({5b620343-cd69-49b8-a7ba-f9d499ee5d3d})|({6eee2d17-f932-4a43-a254-9e2223be8f32})|({e05ba06a-6d6a-4c51-b8fc-60b461ffecaf})|({a5808da1-5b4f-42f2-b030-161fd11a36f7})|({d355bee9-07f0-47d3-8de6-59b8eecba57b})|({a1f8e136-bce5-4fd3-9ed1-f260703a5582})$/","prefs":[],"schema":1517260691761,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.\n","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"70f37cc7-9f8a-4d0f-a881-f0c56934fa75","last_modified":1517260722621},{"guid":"/^({d78d27f4-9716-4f13-a8b6-842c455d6a46})|({bd5ba448-b096-4bd0-9582-eb7a5c9c0948})|({0b24cf69-02b8-407d-83db-e7af04fc1f3e})|({e08d85c5-4c0f-4ce3-9194-760187ce93ba})|({1c7d6d9e-325a-4260-8213-82d51277fc31})|({8a0699a0-09c3-4cf1-b38d-fec25441650c})|({1e68848a-2bb7-425c-81a2-524ab93763eb})$/","prefs":[],"schema":1517168490224,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"805ee80e-0929-4c92-93ed-062b98053f28","last_modified":1517260691755},{"guid":"/^({abec23c3-478f-4a5b-8a38-68ccd500ec42}|{a83c1cbb-7a41-41e7-a2ae-58efcb4dc2e4}|{62237447-e365-487e-8fc3-64ddf37bdaed}|{b12cfdc7-3c69-43cb-a3fb-38981b68a087}|{1a927d5b-42e7-4407-828a-fdc441d0daae}|{dd1cb0ec-be2a-432b-9c90-d64c824ac371}|{82c8ced2-e08c-4d6c-a12b-3e8227d7fc2a}|{87c552f9-7dbb-421b-8deb-571d4a2d7a21})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"c92f2a05-73eb-454e-9583-f6d2382d8bca","last_modified":1516829074251},{"guid":"/^({618baeb9-e694-4c7b-9328-69f35b6a8839}|{b91fcda4-88b0-4a10-9015-9365e5340563}|{04150f98-2d7c-4ae2-8979-f5baa198a577}|{4b1050c6-9139-4126-9331-30a836e75db9}|{1e6f5a54-2c4f-4597-aa9e-3e278c617d38}|{e73854da-9503-423b-ab27-fafea2fbf443}|{a2427e23-d349-4b25-b5b8-46960b218079}|{f92c1155-97b3-40f4-9d5b-7efa897524bb}|{c8e14311-4b2d-4eb0-9a6b-062c6912f50e}|{45621564-b408-4c29-8515-4cf1f26e4bc3}|{27380afd-f42a-4c25-b57d-b9012e0d5d48})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"2d4fe65b-6c02-4461-baa8-dda52e688cf6","last_modified":1516829040469},{"guid":"/^({4dac7c77-e117-4cae-a9f0-6bd89e9e26ab}|{cc689da4-203f-4a0c-a7a6-a00a5abe74c5}|{0eb4672d-58a6-4230-b74c-50ca3716c4b0}|{06a71249-ef35-4f61-b2c8-85c3c6ee5617}|{5280684d-f769-43c9-8eaa-fb04f7de9199}|{c2341a34-a3a0-4234-90cf-74df1db0aa49}|{85e31e7e-3e3a-42d3-9b7b-0a2ff1818b33}|{b5a35d05-fa28-41b5-ae22-db1665f93f6b}|{1bd8ba17-b3ed-412e-88db-35bc4d8771d7}|{a18087bb-4980-4349-898c-ca1b7a0e59cd}|{488e190b-d1f6-4de8-bffb-0c90cc805b62})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9a3fd797-0ab8-4286-9a1b-2b6c97f9075b","last_modified":1516829006347},{"guid":"/^({f6df4ef7-14bd-43b5-90c9-7bd02943789c}|{ccb7b5d6-a567-40a2-9686-a097a8b583dd}|{9b8df895-fcdd-452a-8c46-da5be345b5bc}|{5cf77367-b141-4ba4-ac2a-5b2ca3728e81}|{ada56fe6-f6df-4517-9ed0-b301686a34cc}|{95c7ae97-c87e-4827-a2b7-7b9934d7d642}|{e7b978ae-ffc2-4998-a99d-0f4e2f24da82}|{115a8321-4414-4f4c-aee6-9f812121b446}|{bf153de7-cdf2-4554-af46-29dabfb2aa2d}|{179710ba-0561-4551-8e8d-1809422cb09f}|{9d592fd5-e655-461a-9b28-9eba85d4c97f})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"aae78cd5-6b26-472e-ab2d-db4105911250","last_modified":1516828973824},{"guid":"/^({30972e0a-f613-4c46-8c87-2e59878e7180}|{0599211f-6314-4bf9-854b-84cb18da97f8}|{4414af84-1e1f-449b-ac85-b79f812eb69b}|{2a8bec00-0ab0-4b4d-bd3d-4f59eada8fd8}|{bea8866f-01f8-49e9-92cd-61e96c05d288}|{046258c9-75c5-429d-8d5b-386cfbadc39d}|{c5d359ff-ae01-4f67-a4f7-bf234b5afd6e}|{fdc0601f-1fbb-40a5-84e1-8bbe96b22502}|{85349ea6-2b5d-496a-9379-d4be82c2c13d}|{640c40e5-a881-4d16-a4d0-6aa788399dd2}|{d42328e1-9749-46ba-b35c-cce85ddd4ace})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"750aa293-3742-46b5-8761-51536afecaef","last_modified":1516828938683},{"guid":"/^({d03b6b0f-4d44-4666-a6d6-f16ad9483593}|{767d394a-aa77-40c9-9365-c1916b4a2f84}|{a0ce2605-b5fc-4265-aa65-863354e85058}|{b7f366fa-6c66-46bf-8df2-797c5e52859f}|{4ad16913-e5cb-4292-974c-d557ef5ec5bb}|{3c3ef2a3-0440-4e77-9e3c-1ca8d48f895c}|{543f7503-3620-4f41-8f9e-c258fdff07e9}|{98363f8b-d070-47b6-acc6-65b80acac4f3}|{5af74f5a-652b-4b83-a2a9-f3d21c3c0010}|{484e0ba4-a20b-4404-bb1b-b93473782ae0}|{b99847d6-c932-4b52-9650-af83c9dae649})$/","prefs":[],"schema":1516828883529,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"a29aed6f-6546-4fa2-8131-df5c9a5427af","last_modified":1516828911059},{"guid":"/^({2bb68b03-b528-4133-9fc4-4980fbb4e449}|{231e58ac-0f3c-460b-bb08-0e589360bec7}|{a506c5af-0f95-4107-86f8-3de05e2794c9}|{8886a262-1c25-490b-b797-2e750dd9f36b}|{65072bef-041f-492e-8a51-acca2aaeac70}|{6fa41039-572b-44a4-acd4-01fdaebf608d}|{87ba49bd-daba-4071-aedf-4f32a7e63dbe}|{95d58338-ba6a-40c8-93fd-05a34731dc0e}|{4cbef3f0-4205-4165-8871-2844f9737602}|{1855d130-4893-4c79-b4aa-cbdf6fee86d3}|{87dcb9bf-3a3e-4b93-9c85-ba750a55831a})$/","prefs":[],"schema":1516822896448,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are malicious add-ons that automatically close the Add-ons Manager.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5c092b0d-7205-43a1-aa75-b7a42372fb52","last_modified":1516828883523},{"guid":"/^({fce89242-66d3-4946-9ed0-e66078f172fc})|({0c4df994-4f4a-4646-ae5d-8936be8a4188})|({6cee30bc-a27c-43ea-ac72-302862db62b2})|({e08ebf0b-431d-4ed1-88bb-02e5db8b9443})$/","prefs":[],"schema":1516650096284,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1432560","why":"These are malicious add-ons that make it hard for the user to be removed.","name":"FF AntiVir Monitoring"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9dfeee42-e6a8-49e0-8979-0648f7368239","last_modified":1516744119329},{"guid":"/^(\\{1490068c-d8b7-4bd2-9621-a648942b312c\\})|(\\{d47ebc8a-c1ea-4a42-9ca3-f723fff034bd\\})|(\\{83d6f65c-7fc0-47d0-9864-a488bfcaa376\\})|(\\{e804fa4c-08e0-4dae-a237-8680074eba07\\})|(\\{ea618d26-780e-4f0f-91fd-2a6911064204\\})|(\\{ce93dcc7-f911-4098-8238-7f023dcdfd0d\\})|(\\{7eaf96aa-d4e7-41b0-9f12-775c2ac7f7c0\\})|(\\{b019c485-2a48-4f5b-be13-a7af94bc1a3e\\})|(\\{9b8a3057-8bf4-4a9e-b94b-867e4e71a50c\\})|(\\{eb3ebb14-6ced-4f60-9800-85c3de3680a4\\})|(\\{01f409a5-d617-47be-a574-d54325fe05d1\\})$/","prefs":[],"schema":1516394914836,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are a set of malicious add-ons that block the add-ons manager tab from opening so they can't be uninstalled.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5bf72f70-a611-4845-af3f-d4dabe8862b6","last_modified":1516394982586},{"guid":"/^(\\{ac06c6b2-3fd6-45ee-9237-6235aa347215\\})|(\\{d461cc1b-8a36-4ff0-b330-1824c148f326\\})|(\\{d1ab5ebd-9505-481d-a6cd-6b9db8d65977\\})|(\\{07953f60-447e-4f53-a5ef-ed060487f616\\})|(\\{2d3c5a5a-8e6f-4762-8aff-b24953fe1cc9\\})|(\\{f82b3ad5-e590-4286-891f-05adf5028d2f\\})|(\\{f96245ad-3bb0-46c5-8ca9-2917d69aa6ca\\})|(\\{2f53e091-4b16-4b60-9cae-69d0c55b2e78\\})|(\\{18868c3a-a209-41a6-855d-f99f782d1606\\})|(\\{47352fbf-80d9-4b70-9398-fb7bffa3da53\\})$/","prefs":[],"schema":1516311993443,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1431748","why":"These are a set of malicious add-ons that block the add-ons manager tab from opening so they can't be uninstalled.","name":"FF Tool"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"4ca8206f-bc2a-4428-9439-7f3142dc08db","last_modified":1516394914828},{"guid":"{5b0f6d3c-10fd-414c-a135-dffd26d7de0f}","prefs":[],"schema":1516131689499,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1430577","why":"This is a malicious add-on that executes remote scripts, redirects popular search URLs and tracks users.","name":"P Birthday"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"8088b39a-3e6d-4a17-a22f-3f95c0464bd6","last_modified":1516303320468},{"guid":"{1490068c-d8b7-4bd2-9621-a648942b312c}","prefs":[],"schema":1515267698296,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1428754","why":"This add-on is using a deceptive name and performing unwanted actions on users' systems.","name":"FF Safe Helper"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"674b6e19-f087-4706-a91d-1e723ed6f79e","last_modified":1515433728497},{"guid":"{dfa727cb-0246-4c5a-843a-e4a8592cc7b9}","prefs":[],"schema":1514922095288,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1426582","why":"Version 2.0.0 shipped with a hidden coin miner, which degrades performance in users who have it enabled. Version 1.2.3 currently available on AMO is not affected.","name":"Open With Adobe PDF Reader 2.0.0"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.0","minVersion":"2.0.0"}],"id":"455772a3-8360-4f5a-9a5f-a45b904d0b51","last_modified":1515007270887},{"guid":"{d03b6b0f-4d44-4666-a6d6-f16ad9483593}","prefs":[],"schema":1513366896461,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1425581","why":"This is a malicious add-on posing as a legitimate update.","name":"FF Guard Tool (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"10d9ce89-b8d4-4b53-b3d7-ecd192681f4e","last_modified":1513376470395},{"guid":"{7e907a15-0a4c-4ff4-b64f-5eeb8f841349}","prefs":[],"schema":1510083698490,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate update.","name":"Manual Update"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"f7569261-f575-4719-8202-552b20d013b0","last_modified":1510168860382},{"guid":"{3602008d-8195-4860-965a-d01ac4f9ca96}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"28c805a9-e692-4ef8-b3ae-14e085c19ecd","last_modified":1509120934909},{"guid":"{87010166-e3d0-4db5-a394-0517917201df}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"84dd8a02-c879-4477-8ea7-bf2f225b0940","last_modified":1509120881470},{"guid":"{8ab60777-e899-475d-9a4f-5f2ee02c7ea4}","prefs":[],"schema":1509120801051,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.\n","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"ccebab59-7190-4258-8faa-a0b752dd5301","last_modified":1509120831329},{"guid":"{368eb817-31b4-4be9-a761-b67598faf9fa}","prefs":[],"schema":1509046897080,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1411885","why":"This is a malicious add-on posing as a legitimate antivirus.","name":"Manual Antivirus"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"9abc7502-bd6f-40d7-b035-abe721345360","last_modified":1509120801043},{"guid":"fi@dictionaries.addons.mozilla.org","prefs":[],"schema":1508701297180,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1407147","why":"This add-on is causing frequent crashes in Firefox 56.","name":"Finnish spellchecker"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.1.0","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"56.0a1"}]}],"id":"22431713-a93b-40f4-8264-0b341b5f6454","last_modified":1508856488536},{"guid":"firefox@mega.co.nz","prefs":[],"schema":1506800496781,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1404290","why":"Add-on is causing tabs to load blank.","name":"Mega.nz"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.16.1","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"56.0a1"}]}],"id":"a84e6eba-4bc1-4416-b481-9b837d39f9f0","last_modified":1506963401477},{"guid":"@68eba425-7a05-4d62-82b1-1d6d5a51716b","prefs":[],"schema":1505072496256,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1398905","why":"Misleads users into thinking this is a security and privacy tool (also distributed on a site that makes it look like an official Mozilla product).","name":"SearchAssist Incognito"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0"}],"id":"595e0e53-b76b-4188-a160-66f29c636094","last_modified":1505211411253},{"guid":"{efda3854-2bd9-45a1-9766-49d7ff18931d}","prefs":[],"schema":1503344500341,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1392625","why":"Add-on injects remote code into privileged scope.","name":"Smart Referer"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.8.17.2","minVersion":"0"}],"id":"d83011de-67a4-479b-a778-916a7232095b","last_modified":1503411102265},{"guid":"@H99KV4DO-UCCF-9PFO-9ZLK-8RRP4FVOKD9O","prefs":[],"schema":1502483549048,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1340877","why":"This is a malicious add-on that is being installed silently.","name":"FF Adr (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"5df16afc-c804-43c9-9de5-f1835403e5fb","last_modified":1502483601731},{"guid":"@DA3566E2-F709-11E5-8E87-A604BC8E7F8B","prefs":[],"schema":1502480491460,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1340877","why":"This is a malicious add-on that is being installed silently into users' systems.","name":"SimilarWeb (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"0a47a2f7-f07c-489b-bd39-88122a2dfe6a","last_modified":1502483549043},{"guid":"xdict@www.iciba.com","prefs":[],"schema":1501098091500,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1384497","why":"This add-on has been discontinued and is creating a prompt loop that blocks users from using Firefox.","name":"PowerWord Grab Word Extension"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.3.1","minVersion":"0"}],"id":"28736359-700e-4b61-9c50-0b533a6bac55","last_modified":1501187580933},{"guid":"{3B4DE07A-DE43-4DBC-873F-05835FF67DCE}","prefs":[],"schema":1496950889322,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1371392","why":"This add-on performs hidden actions that cause the users' systems to act as a botnet.","name":"The Safe Surfing (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"510bbd9b-b883-4837-90ab-8e353e27e1be","last_modified":1496951442076},{"guid":"WebProtection@360safe.com","prefs":[],"schema":1496846005095,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1336635","who":"All users of Firefox 52 and above who have this add-on installed.","why":"This add-on breaks the Firefox user interface starting with version 52.","name":"360 Internet Protection versions 5.0.0.1009 and lower"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"5.0.0.1009","minVersion":"0"}],"id":"e16408c3-4e08-47fd-85a9-3cbbce534e95","last_modified":1496849965060},{"guid":"html5@encoding","prefs":[],"schema":1496788543767,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1370847","who":"All users.","why":"This malicious add-on targets a certain user group and spies on them.","name":"HTML5 Encoding (Malicious), all versions"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"c806b01c-3352-4083-afd9-9a8ab6e00b19","last_modified":1496833261424},{"guid":"/^({95E84BD3-3604-4AAC-B2CA-D9AC3E55B64B}|{E3605470-291B-44EB-8648-745EE356599A}|{95E5E0AD-65F9-4FFC-A2A2-0008DCF6ED25}|{FF20459C-DA6E-41A7-80BC-8F4FEFD9C575}|{6E727987-C8EA-44DA-8749-310C0FBE3C3E}|{12E8A6C2-B125-479F-AB3C-13B8757C7F04}|{EB6628CF-0675-4DAE-95CE-EFFA23169743})$/","prefs":[],"schema":1494022576295,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1362585","why":"All of these add-ons have been identified as malware, and are being installed in Firefox globally, most likely via a malicious application installer.","name":"Malicious globally-installed add-ons"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"3fd71895-7fc6-4f3f-aa22-1cbb0c5fd922","last_modified":1494024191520},{"guid":"@safesearchscoutee","prefs":[],"schema":1494013289942,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1362553","why":"This add-on intercepts queries sent to search engines and replaces them with its own, without user consent.","name":"SafeSearch Incognito (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0"}],"id":"edad04eb-ea16-42f3-a4a7-20dded33cc37","last_modified":1494022568654},{"guid":"{0D2172E4-C5AE-465A-B80D-53A840275B5E}","prefs":[],"schema":1493332768943,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1359473","who":"All users of Thunderbird 52 and above, using a version of the Priority Switcher add-on before version 0.7","why":"This add-on is causing recurring startup crashes in Thunderbird.","name":"Priority Switcher for Thunderbird before version 0.7"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.6.999","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"52.0a1"}]}],"id":"8c8af415-46db-40be-a66e-38e3762493bd","last_modified":1493332986987},{"guid":"msktbird@mcafee.com","prefs":[],"schema":1493150718059,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1354912","why":"These versions of this add-on are known to cause frequent crashes in Thunderbird.","name":"McAfee Anti-Spam Thunderbird Extension 2.0 and lower"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"0"}]}],"id":"9e86d1ff-727a-45e3-9fb6-17f32666daf2","last_modified":1493332747360},{"guid":"/^(\\{11112503-5e91-4299-bf4b-f8c07811aa50\\})|(\\{501815af-725e-45be-b0f2-8f36f5617afc\\})$/","prefs":[],"schema":1491421290217,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1354045","why":"This add-on steals user credentials for popular websites from Facebook.","name":"Flash Player Updater (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c142360c-4f93-467e-9717-b638aa085d95","last_modified":1491472107658},{"guid":"fr@fbt.ovh","prefs":[],"schema":1490898754477,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351689","why":"Scam add-on that silently steals user credentials of popular websites","name":"Adobe Flash Player (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0f8344d0-8211-49a1-81be-c0084b3da9b1","last_modified":1490898787752},{"guid":"/^\\{(9321F452-96D5-11E6-BC3E-3769C7AD2208)|({18ED1ECA-96D3-11E6-A373-BD66C7AD2208})\\}$/","prefs":[],"schema":1490872899765,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351710","why":"These add-ons modify websites and add deceptive or abusive content","name":"Scamming add-ons (Malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d6425f24-8c9e-4c0a-89b4-6890fc68d5c9","last_modified":1490898748265},{"guid":"/^(test2@test\\.com)|(test3@test\\.com)|(mozilla_cc2\\.2@internetdownloadmanager\\.com)$/","prefs":[],"schema":1490557289817,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1351095","who":"All users who have any of these add-ons installed.","why":"Old versions of the Internet Download Manager Integration add-on cause performance and stability problems in Firefox 53 and above.","name":"IDM Integration forks"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"53.0a1"}]}],"id":"9085fdba-8498-46a9-b9fd-4c7343a15c62","last_modified":1490653926191},{"guid":"mozilla_cc2@internetdownloadmanager.com","prefs":[],"schema":1489007018796,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1338832","who":"All users who have these versions of the add-on installed.","why":"Old versions of the Internet Download Manager Integration add-on cause performance and stability problems in Firefox 53 and above.","name":"IDM Integration"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"6.26.11","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"53.0a1"}]}],"id":"d33f6d48-a555-49dd-96ff-8d75473403a8","last_modified":1489514734167},{"guid":"InternetProtection@360safe.com","prefs":[],"schema":1489006712382,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1336635","who":"All Firefox users who have this add-on installed.","why":"This add-on breaks the Firefox user interface starting with version 52.","name":"360 Internet Protection"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"5.0.0.1002","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"52.0a1"}]}],"id":"89a61123-79a2-45d1-aec2-97afca0863eb","last_modified":1489006816246},{"guid":"{95E84BD3-3604-4AAC-B2CA-D9AC3E55B64B}","prefs":[],"schema":1487179851382,"details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1338690","who":"All users who have this add-on installed.","why":"This is a malicious add-on that is silently installed in users' systems.","name":"youtube adblock (malware)"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"04b25e3d-a725-493e-be07-cbd74fb37ea7","last_modified":1487288975999},{"guid":"ext@alibonus.com","prefs":[],"schema":1485297431051,"blockID":"i1524","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1333471","who":"All Firefox users who have these versions installed.","why":"Versions 1.20.9 and lower of this add-on contain critical security issues.","name":"Alibonus 1.20.9 and lower","created":"2017-01-24T22:45:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.20.9","minVersion":"0","targetApplication":[]}],"id":"a015d5a4-9184-95db-0c74-9262af2332fa","last_modified":1485301116629},{"guid":"{a0d7ccb3-214d-498b-b4aa-0e8fda9a7bf7}","prefs":[],"schema":1485295513652,"blockID":"i1523","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1314332","who":"All Firefox users who have these versions of the Web of Trust add-on installed.","why":"Versions 20170120 and lower of the Web of Trust add-on send excessive user data to its service, which has been reportedly shared with third parties without sufficient sanitization. These versions are also affected by a vulnerability that could lead to unwanted remote code execution.","name":"Web of Trust 20170120 and lower","created":"2017-01-24T22:01:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"20170120","minVersion":"0","targetApplication":[]}],"id":"2224c139-9b98-0900-61c1-04031de11ad3","last_modified":1485297214072},{"guid":"/^(ciscowebexstart1@cisco\\.com|ciscowebexstart_test@cisco\\.com|ciscowebexstart@cisco\\.com|ciscowebexgpc@cisco\\.com)$/","prefs":[],"schema":1485212610474,"blockID":"i1522","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1333225","who":"All Firefox users who have any Cisco WebEx add-ons installed.","why":"A critical security vulnerability has been discovered in Cisco WebEx add-ons that enable malicious websites to execute code on the user's system.","name":"Cisco WebEx add-ons","created":"2017-01-23T22:55:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.1","minVersion":"1.0.0","targetApplication":[]}],"id":"30368779-1d3b-490a-0a34-253085af7754","last_modified":1485215014902},{"guid":"{de71f09a-3342-48c5-95c1-4b0f17567554}","prefs":[],"schema":1484335370642,"blockID":"i1493","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1329654","who":"All users who have this add-on installed.","why":"This is a malicious add-on that is installed using a fake name. It changes search and homepage settings.","name":"Search for Firefox Convertor (malware)","created":"2017-01-12T22:17:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.3.9","minVersion":"0","targetApplication":[]}],"id":"d6ec9f54-9945-088e-ba68-40117eaba24e","last_modified":1484867614757},{"guid":"googlotim@gmail.com","prefs":[],"schema":1483389810787,"blockID":"i1492","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1328594","who":"All users who have Savogram version 1.3.2 installed. Version 1.3.1 doesn't have this problem and can be installed from the add-on page. Note that this is an older version, so affected users won't be automatically updated to it. New versions should correct this problem if they become available.","why":"Version 1.3.2 of this add-on loads remote code and performs DOM injection in an unsafe manner.","name":"Savogram 1.3.2","created":"2017-01-05T19:58:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.2","minVersion":"1.3.2","targetApplication":[]}],"id":"0756ed76-7bc7-ec1e-aba5-3a9fac2107ba","last_modified":1483646608603},{"guid":"support@update-firefox.com","prefs":[],"schema":1483387107003,"blockID":"i21","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=629717","who":"All users of the add-on in all Mozilla applications.","why":"This add-on is adware/spyware masquerading as a Firefox update mechanism.","name":"Browser Update (spyware)","created":"2011-01-31T16:23:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dfb06be8-3594-28e4-d163-17e27119f15d","last_modified":1483389809169},{"guid":"{2224e955-00e9-4613-a844-ce69fccaae91}","prefs":[],"schema":1483387107003,"blockID":"i7","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=512406","who":"All users of Internet Saving Optimizer for all Mozilla applications.","why":"This add-on causes a high volume of Firefox crashes and is considered malware.","name":"Internet Saving Optimizer (extension)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9efb796-97c2-6434-d28f-acc83436f8e5","last_modified":1483389809147},{"guid":"supportaccessplugin@gmail.com","prefs":[],"schema":1483387107003,"blockID":"i43","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=693673","who":"All users with Firefox Access Plugin installed","why":"This add-on is spyware that reports all visited websites to a third party with no user value.","name":"Firefox Access Plugin (spyware)","created":"2011-10-11T11:24:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ed230a4-e174-262a-55ab-0c33f93a2529","last_modified":1483389809124},{"guid":"{8CE11043-9A15-4207-A565-0C94C42D590D}","prefs":[],"schema":1483387107003,"blockID":"i10","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=541302","who":"All users of this add-on in all Mozilla applications.","why":"This add-on secretly hijacks all search results in most major search engines and masks as a security add-on.","name":"Internal security options editor (malware)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e2e0ac09-6d68-75f5-2424-140f51904876","last_modified":1483389809102},{"guid":"youtube@youtube2.com","prefs":[],"schema":1483387107003,"blockID":"i47","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=713050","who":"All users with any version of Free Cheesecake Factory installed on any Mozilla product.","why":"This add-on hijacks your Facebook account.","name":"Free Cheesecake Factory (malware)","created":"2011-12-22T13:11:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"85f5c1db-433b-bee3-2a3b-325165cacc6e","last_modified":1483389809079},{"guid":"admin@youtubespeedup.com","prefs":[],"schema":1483387107003,"blockID":"i48","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=714221","who":"All users with any version of Youtube Speed UP! installed on any Mozilla product.","why":"This add-on hijacks your Facebook account.","name":"Youtube Speed UP! (malware)","created":"2011-12-29T19:48:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a93922c4-8a8a-5230-8f76-76fecb0653b6","last_modified":1483389809057},{"guid":"{E8E88AB0-7182-11DF-904E-6045E0D72085}","prefs":[],"schema":1483387107003,"blockID":"i13","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=578085","who":"All users of this add-on for all Mozilla applications.","why":"This add-on intercepts website login credentials and is malware. For more information, please read our security announcement.","name":"Mozilla Sniffer (malware)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ebbd6de9-fc8a-3e5b-2a07-232bee589c7c","last_modified":1483389809035},{"guid":"sigma@labs.mozilla","prefs":[],"schema":1483387107003,"blockID":"i44","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=690819","who":"All users of Lab Kit in all versions of Firefox.","why":"The Lab Kit add-on has been retired due to compatibility issues with Firefox 7 and future Firefox browser releases. You can still install Mozilla Labs add-ons individually.\r\n\r\nFor more information, please read this announcement.","name":"Mozilla Labs: Lab Kit","created":"2011-10-11T11:51:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d614e9cd-220f-3a19-287b-57e122f8c4b5","last_modified":1483389809012},{"guid":"/^(jid0-S9kkzfTvEmC985BVmf8ZOzA5nLM@jetpack|jid1-qps14pkDB6UDvA@jetpack|jid1-Tsr09YnAqIWL0Q@jetpack|shole@ats.ext|{38a64ef0-7181-11e3-981f-0800200c9a66}|eochoa@ualberta.ca)$/","prefs":[],"schema":1483376308298,"blockID":"i1424","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:22:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0699488d-2a19-6735-809e-f229849fe00b","last_modified":1483378113482},{"guid":"pink@rosaplugin.info","prefs":[],"schema":1482945809444,"blockID":"i84","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743484","who":"All Firefox users who have this add-on installed","why":"Add-on acts like malware and performs user actions on Facebook without their consent.","name":"Facebook Rosa (malware)","created":"2012-04-09T10:13:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"66ad8de9-311d-076c-7356-87fde6d30d8f","last_modified":1482945810971},{"guid":"videoplugin@player.com","prefs":[],"schema":1482945809444,"blockID":"i90","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=752483","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Flash Player update. It can hijack Google searches and Facebook accounts.","name":"FlashPlayer 11 (malware)","created":"2012-05-07T08:58:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d25943f1-39ef-b9ec-ab77-baeef3498365","last_modified":1482945810949},{"guid":"youtb3@youtb3.com","prefs":[],"schema":1482945809444,"blockID":"i60","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=723753","who":"All Firefox users who have this extension installed.","why":"Malicious extension installed under false pretenses.","name":"Video extension (malware)","created":"2012-02-02T16:38:41Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cae3093f-a7b3-5352-a264-01dbfbf347ce","last_modified":1482945810927},{"guid":"{8f42fb8b-b6f6-45de-81c0-d6d39f54f971}","prefs":[],"schema":1482945809444,"blockID":"i82","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743012","who":"All Firefox users who have installed this add-on.","why":"This add-on maliciously manipulates Facebook and is installed under false pretenses.","name":"Face Plus (malware)","created":"2012-04-09T10:04:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"09319ab3-55e7-fec1-44e0-84067d014b9b","last_modified":1482945810904},{"guid":"cloudmask@cloudmask.com","prefs":[],"schema":1482945809444,"blockID":"i1233","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1280431","who":"Any user who has version 2.0.788, or earlier, installed.","why":"These versions of the add-on (before 2.0.788) execute code from a website in a privileged local browser context, potentially allowing dangerous, unreviewed, actions to affect the user's computer. This is fixed in later versions.","name":"CloudMask","created":"2016-06-17T14:31:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.788","minVersion":"0","targetApplication":[]}],"id":"2a8b40c7-a1d2-29f4-b7d7-ccfc5066bae1","last_modified":1482945810881},{"guid":"{95ff02bc-ffc6-45f0-a5c8-619b8226a9de}","prefs":[],"schema":1482945809444,"blockID":"i105","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.\r\n","name":"Eklenti D\u00fcnyas\u0131 (malware)","created":"2012-06-08T14:34:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"afbbc08d-2414-f51e-fdb8-74c0a2d90323","last_modified":1482945810858},{"guid":"{fa277cfc-1d75-4949-a1f9-4ac8e41b2dfd}","prefs":[],"schema":1482945809444,"blockID":"i77","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=738419","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware that is installed under false pretenses as an Adobe plugin.","name":"Adobe Flash (malware)","created":"2012-03-22T14:39:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81753a93-382d-5f9d-a4ca-8a21b679ebb1","last_modified":1482945810835},{"guid":"youtube@youtube3.com","prefs":[],"schema":1482945809444,"blockID":"i57","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722823","who":"All Firefox users that have installed this add-on.","why":"Malware installed on false pretenses.","name":"Divx 2012 Plugin (malware)","created":"2012-01-31T13:54:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4a93a0eb-a513-7272-6199-bc4d6228ff50","last_modified":1482945810811},{"guid":"{392e123b-b691-4a5e-b52f-c4c1027e749c}","prefs":[],"schema":1482945809444,"blockID":"i109","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=769781","who":"All Firefox users who have this add-on installed.","why":"This add-on pretends to be developed by Facebook and injects scripts that manipulate users' Facebook accounts.","name":"Zaman Tuneline Hay\u0131r! (malware)","created":"2012-06-29T13:20:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9a805aa-cae7-58d6-5a53-2af4442e4cf6","last_modified":1482945810788},{"guid":"msntoolbar@msn.com","prefs":[],"schema":1482945809444,"blockID":"i18","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of Bing Bar 6.0 and older for all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Bing Bar","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"6.*","minVersion":" 0","targetApplication":[]}],"id":"9b2f2039-b997-8993-d6dc-d881bc1ca7a1","last_modified":1482945810764},{"guid":"yasd@youasdr3.com","prefs":[],"schema":1482945809444,"blockID":"i104","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.\r\n","name":"Play Now (malware)","created":"2012-06-08T14:33:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8a352dff-d09d-1e78-7feb-45dec7ace5a5","last_modified":1482945810740},{"guid":"fdm_ffext@freedownloadmanager.org","prefs":[],"schema":1482945809444,"blockID":"i2","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=408445","who":"Users of Firefox 3 and later with versions 1.0 through 1.3.1 of Free Download Manager","why":"This add-on causes a high volume of crashes.","name":"Free Download Manager","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.1","minVersion":"1.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.0a1"}]}],"id":"fc46f8e7-0489-b90f-a373-d93109479ca5","last_modified":1482945810393},{"guid":"flash@adobe.com","prefs":[],"schema":1482945809444,"blockID":"i56","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722526","who":"All Firefox users who have this add-on installed.","why":"This add-on poses as an Adobe Flash update and injects malicious scripts into web pages. It hides itself in the Add-ons Manager.","name":"Adobe Flash Update (malware)","created":"2012-01-30T15:41:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"696db959-fb0b-8aa4-928e-65f157cdd77a","last_modified":1482945810371},{"guid":"youtubeer@youtuber.com","prefs":[],"schema":1482945809444,"blockID":"i66","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=726787","who":"All Firefox users who have installed this add-on.","why":"Add-on behaves maliciously, and is installed under false pretenses.","name":"Plug VDS (malware)","created":"2012-02-13T15:44:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0878ce4e-b476-ffa3-0e06-21a65b7917a1","last_modified":1482945810348},{"guid":"{B13721C7-F507-4982-B2E5-502A71474FED}","prefs":[],"schema":1482945809444,"blockID":"i8","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=627278","who":"Users of all versions of the original Skype Toolbar in all versions of Firefox.","why":"This add-on causes a high volume of Firefox crashes and introduces severe performance issues. Please update to the latest version. For more information, please read our announcement.","name":"Original Skype Toolbar","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5a320611-59a3-0eee-bb30-9052be870e00","last_modified":1482945810326},{"guid":"yslow@yahoo-inc.com","prefs":[],"schema":1482945809444,"blockID":"i11","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=542686","who":"Users of YSlow version 2.0.5 for Firefox 3.5.7 and later.","why":"This add-on causes a high volume of Firefox crashes and other stability issues. Users should update to the latest version.","name":"YSlow","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.5","minVersion":"2.0.5","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.5.7"}]}],"id":"a9b34e8f-45ce-9217-b791-98e094c26352","last_modified":1482945810303},{"guid":"youtube@youtuber.com","prefs":[],"schema":1482945809444,"blockID":"i63","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=724691","who":"All Firefox users who have installed this add-on.","why":"Installs under false pretenses and delivers malware.","name":"Mozilla Essentials (malware)","created":"2012-02-06T15:39:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"18216e6f-9d70-816f-4d4c-63861f43ff3c","last_modified":1482945810281},{"guid":"flash@adobee.com","prefs":[],"schema":1482945809444,"blockID":"i83","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=743497","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware installed under false pretenses.","name":"FlashPlayer 11 (malware)","created":"2012-04-09T10:08:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"09bb4661-331c-f7ba-865b-9e085dc437af","last_modified":1482945810259},{"guid":"youtube@2youtube.com","prefs":[],"schema":1482945809444,"blockID":"i71","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=730399","who":"All Firefox users who have installed this add-on.","why":"Extension is malware, installed under false pretenses.","name":"YouTube extension (malware)","created":"2012-02-27T10:23:23Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5d389c1f-b3a0-b06f-6ffb-d1e8aa055e3c","last_modified":1482945810236},{"guid":"webmaster@buzzzzvideos.info","prefs":[],"schema":1482945809444,"blockID":"i58","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722844","who":"All Firefox users who have installed this add-on.","why":"Malware add-on that is installed under false pretenses.","name":"Buzz Video (malware)","created":"2012-01-31T14:51:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7aab105-e2c2-42f5-d9be-280eb9c0c8f7","last_modified":1482945810213},{"guid":"play5@vide04flash.com","prefs":[],"schema":1482945809444,"blockID":"i92","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=755443","who":"All Firefox users who have this add-on installed.","why":"This add-on impersonates a Flash Player update (poorly), and inserts malicious scripts into Facebook.","name":"Lastest Flash PLayer (malware)","created":"2012-05-15T13:27:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7190860e-fc1f-cd9f-5d25-778e1e9043b2","last_modified":1482945810191},{"guid":"support3_en@adobe122.com","prefs":[],"schema":1482945809444,"blockID":"i97","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759164","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as the Flash Player plugin.","name":"FlashPlayer 11 (malware)","created":"2012-05-28T13:42:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"decf93a1-2bb0-148c-a1a6-10b3757b554b","last_modified":1482945810168},{"guid":"a1g0a9g219d@a1.com","prefs":[],"schema":1482945809444,"blockID":"i73","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=736275","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as Flash Player. It steals user cookies and sends them to a remote location.","name":"Flash Player (malware)","created":"2012-03-15T15:03:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6dd66b43-897d-874a-2227-54e240b8520f","last_modified":1482945810146},{"guid":"ghostviewer@youtube2.com","prefs":[],"schema":1482945809444,"blockID":"i59","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=723683","who":"All Firefox users who have installed this add-on.","why":"Malicious add-on that automatically posts to Facebook.","name":"Ghost Viewer (malware)","created":"2012-02-02T16:32:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"06dfe833-8c3d-90ee-3aa8-37c3c28f7c56","last_modified":1482945810123},{"guid":"{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}","prefs":[],"schema":1482945809444,"blockID":"i19","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=621660","who":"Users of Stylish version 1.1b1 for Firefox.","why":"Version 1.1b1 of this add-on causes compatibility issues with Firefox. Users should update to the latest version.","name":"Stylish","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.1b1","minVersion":"1.1b1","targetApplication":[]}],"id":"aaea37e1-ff86-4565-8bd5-55a6bf942791","last_modified":1482945810101},{"guid":"kdrgun@gmail.com","prefs":[],"schema":1482945809444,"blockID":"i103","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=763065","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that inserts scripts into Facebook and hijacks the user's session.","name":"Timeline Kapat (malware)","created":"2012-06-08T14:32:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a9a46ab2-2f56-1046-201c-5faa3435e248","last_modified":1482945810078},{"guid":"youtube2@youtube2.com","prefs":[],"schema":1482945809444,"blockID":"i67","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=728476","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware, installed under false pretenses.","name":"Youtube Online (malware)","created":"2012-02-18T09:10:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"14650ece-295b-a667-f9bc-a3d973e2228c","last_modified":1482945810055},{"guid":"masterfiler@gmail.com","prefs":[],"schema":1482945809444,"blockID":"i12","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=542081","who":"All users of this add-on for all Mozilla applications.","why":"This add-on is malware and attempts to install a Trojan on the user's computer.","name":"Master File (malware)","created":"2010-02-05T15:01:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a256d79d-5af8-92e9-a29d-350adf822efe","last_modified":1482945810032},{"guid":"{847b3a00-7ab1-11d4-8f02-006008948af5}","prefs":[],"schema":1482945809444,"blockID":"i9","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=531047","who":"Users of Enigmail versions older than 0.97a for Thunderbird 3 and later.","why":"This add-on causes a high volume of crashes and other stability issues. Users should update Enigmail.","name":"Enigmail","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.97a","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"3.0pre"}]}],"id":"115f46b6-059d-202a-4373-2ca79b096347","last_modified":1482945810003},{"guid":"mozilla_cc@internetdownloadmanager.com","prefs":[],"schema":1482945809444,"blockID":"i14","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=578443","who":"Users of Firefox 4 and later with Internet Download Manager version 6.9.8 and older.","why":"This add-on causes a high volume of crashes and has other stability issues.","name":"Internet Download Manager","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"6.9.8","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"773ffcfb-75d1-081d-7431-ebe3fa5dbb44","last_modified":1482945809979},{"guid":"admin@youtubeplayer.com","prefs":[],"schema":1482945809444,"blockID":"i51","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=717165","who":"All Firefox users with this extension installed.","why":"This add-on is malware, doing nothing more than inserting advertisements into websites through iframes.","name":"Youtube player (malware)","created":"2012-01-18T14:34:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"16b2ce94-88db-0d79-33fc-a93070ceb509","last_modified":1482945809957},{"guid":"personas@christopher.beard","prefs":[],"schema":1482945809444,"blockID":"i15","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=590978","who":"All users of Personas Plus 1.6 in all versions of Firefox.","why":"This version of Personas Plus is incompatible with certain Firefox functionality and other add-ons. Users should upgrade to the latest version.","name":"Personas Plus","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.6","minVersion":"1.6","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"3.6.*","minVersion":"3.6"}]}],"id":"e36479c6-ca00-48d4-4fd9-ec677fd032da","last_modified":1482945809934},{"guid":"youtubeee@youtuber3.com","prefs":[],"schema":1482945809444,"blockID":"i96","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=758503","who":"All Firefox users who have installed this add-on.","why":"This is a malicious add-on that is disguised as a DivX plugin.","name":"Divx 2012 Plugins (malware)","created":"2012-05-25T09:26:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f01be9cb-5cf2-774a-a4d7-e210a24db5b9","last_modified":1482945809912},{"guid":"{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}","prefs":[],"schema":1482945809444,"blockID":"i17","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of version 2.2 of this add-on in all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Default Manager (Microsoft)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.2","minVersion":"2.2","targetApplication":[]}],"id":"38be28ac-2e30-37fa-4332-852a55fafb43","last_modified":1482945809886},{"guid":"{68b8676b-99a5-46d1-b390-22411d8bcd61}","prefs":[],"schema":1482945809444,"blockID":"i93","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=755635","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that post content on Facebook accounts and steals user data.","name":"Zaman T\u00fcnelini Kald\u0131r! (malware)","created":"2012-05-16T10:44:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"733aff15-9b1f-ec04-288f-b78a55165a1c","last_modified":1482945809863},{"guid":"applebeegifts@mozilla.doslash.org","prefs":[],"schema":1482945809444,"blockID":"i54","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=721562","who":"All Firefox users that install this add-on.","why":"Add-on is malware installed under false pretenses.","name":"Applebees Gift Card (malware)","created":"2012-01-26T16:17:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1372c8ab-5452-745a-461a-aa78e3e12c4b","last_modified":1482945809840},{"guid":"activity@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i65","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=726803","who":"All Firefox users who have installed this add-on.","why":"Add-on behaves maliciously and poses as an official Facebook add-on.","name":"Facebook extension (malware)","created":"2012-02-13T15:41:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"79ad1c9b-0828-7823-4574-dd1cdd46c3d6","last_modified":1482945809437},{"guid":"jid0-EcdqvFOgWLKHNJPuqAnawlykCGZ@jetpack","prefs":[],"schema":1482945112982,"blockID":"i62","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=724650","who":"All Firefox users who have installed this add-on.","why":"Add-on is installed under false pretenses and delivers malware.","name":"YouTube extension (malware)","created":"2012-02-06T14:46:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5ae1e642-b53c-54c0-19e7-5562cfdac3a3","last_modified":1482945809415},{"guid":"{B7082FAA-CB62-4872-9106-E42DD88EDE45}","prefs":[],"schema":1482945112982,"blockID":"i25","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=637542","who":"Users of McAfee SiteAdvisor below version 3.3.1 for Firefox 4.\r\n\r\nUsers of McAfee SiteAdvisor 3.3.1 and below for Firefox 5 and higher.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"McAfee SiteAdvisor","created":"2011-03-14T15:53:07Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.3.0.*","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1"}]}],"id":"c950501b-1f08-2ab2-d817-7c664c0d16fe","last_modified":1482945809393},{"guid":"{B7082FAA-CB62-4872-9106-E42DD88EDE45}","prefs":[],"schema":1482945112982,"blockID":"i38","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=660111","who":"Users of McAfee SiteAdvisor below version 3.3.1 for Firefox 4.\r\n\r\nUsers of McAfee SiteAdvisor 3.3.1 and below for Firefox 5 and higher.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"McAfee SiteAdvisor","created":"2011-05-27T13:55:02Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"3.3.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"5.0a1"}]}],"id":"f11de388-4511-8d06-1414-95d3b2b122c5","last_modified":1482945809371},{"guid":"{3f963a5b-e555-4543-90e2-c3908898db71}","prefs":[],"schema":1482945112982,"blockID":"i6","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=527135","who":"Users of AVG SafeSearch version 8.5 and older for all Mozilla applications.","why":"This add-on causes a high volume of crashes and causes other stability issues.","name":"AVG SafeSearch","created":"2009-06-17T13:12:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"8.5","minVersion":"0","targetApplication":[]}],"id":"0d6f7d4c-bf5d-538f-1ded-ea4c6b775617","last_modified":1482945809348},{"guid":"langpack-vi-VN@firefox.mozilla.org","prefs":[],"schema":1482945112982,"blockID":"i3","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=432406","who":"Users of Vietnamese Language Pack version 2.0 for all Mozilla applications.","why":"Corrupted files. For more information, please see this blog post.","name":"Vietnamese Language Pack","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0","minVersion":"2.0","targetApplication":[]}],"id":"51d4b581-d21c-20a1-6147-b17c3adc7867","last_modified":1482945809326},{"guid":"youtube@youtube7.com","prefs":[],"schema":1482945112982,"blockID":"i55","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=721646","who":"All Firefox users with this add-on installed.","why":"This is malware posing as video software.","name":"Plugin Video (malware)","created":"2012-01-27T09:39:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"08ceedf5-c7c1-f54f-db0c-02f01f0e319a","last_modified":1482945809304},{"guid":"crossriderapp3924@crossrider.com","prefs":[],"schema":1482945112982,"blockID":"i76","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=738282","who":"All Firefox users who have installed this add-on.","why":"This add-on compromises Facebook privacy and security and spams friends lists without user intervention.","name":"Fblixx (malware)","created":"2012-03-22T10:38:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39d0a019-62fb-837b-1f1f-6831e56442b5","last_modified":1482945809279},{"guid":"{45147e67-4020-47e2-8f7a-55464fb535aa}","prefs":[],"schema":1482945112982,"blockID":"i86","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=748993","who":"All Firefox users who have this add-on installed.","why":"This add-on injects scripts into Facebook and performs malicious activity.","name":"Mukemmel Face+","created":"2012-04-25T16:33:21Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"960443f9-cf48-0b71-1ff2-b8c34a3411ea","last_modified":1482945809255},{"guid":"{4B3803EA-5230-4DC3-A7FC-33638F3D3542}","prefs":[],"schema":1482945112982,"blockID":"i4","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=441649","who":"Users of Firefox 3 and later with version 1.2 of Crawler Toolbar","why":"This add-on causes a high volume of crashes.","name":"Crawler Toolbar","created":"2008-07-08T10:23:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2","minVersion":"1.2","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.0a1"}]}],"id":"a9818d53-3a6a-8673-04dd-2a16f5644215","last_modified":1482945809232},{"guid":"flashupdate@adobe.com","prefs":[],"schema":1482945112982,"blockID":"i68","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=722526","who":"All Firefox users who have this add-on installed.","why":"Add-on is malware, installed under false pretenses.","name":"Flash Update (malware)","created":"2012-02-21T13:55:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ba5b46e-790d-5af2-9580-a5f1e6e65522","last_modified":1482945809208},{"guid":"plugin@youtubeplayer.com","prefs":[],"schema":1482945112982,"blockID":"i127","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=783356","who":"All users who have this add-on installed.","why":"This add-on tries to pass as a YouTube player and runs malicious scripts on webpages.","name":"Youtube Facebook Player (malware)","created":"2012-08-16T13:03:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"17a8bece-e2df-a55d-8a72-95faff028b83","last_modified":1482945809185},{"guid":"GifBlock@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i79","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=739482","who":"All Firefox users who have installed this extension.","why":"This extension is malicious and is installed under false pretenses.","name":"Facebook Essentials (malware)","created":"2012-03-27T10:53:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"728451e8-1273-d887-37e9-5712b1cc3bff","last_modified":1482945809162},{"guid":"ff-ext@youtube","prefs":[],"schema":1482945112982,"blockID":"i52","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=719296","who":"All Firefox users that have this add-on installed.","why":"This add-on poses as a YouTube player while posting spam into Facebook account.","name":"Youtube player (malware)","created":"2012-01-19T08:26:35Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cd2dd72a-dd52-6752-a0cd-a4b312fd0b65","last_modified":1482945809138},{"guid":"ShopperReports@ShopperReports.com","prefs":[],"schema":1482945112982,"blockID":"i22","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=630191","who":"Users of Shopper Reports version 3.1.22.0 in Firefox 4 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"Shopper Reports","created":"2011-02-09T17:03:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.1.22.0","minVersion":"3.1.22.0","targetApplication":[]}],"id":"f26b049c-d856-750f-f050-996e6bec7cbb","last_modified":1482945809115},{"guid":"{27182e60-b5f3-411c-b545-b44205977502}","prefs":[],"schema":1482945112982,"blockID":"i16","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=599971","who":"Users of version 1.0 of this add-on in all versions of Firefox.","why":"This add-on has security issues and was blocked at Microsoft's request. For more information, please see this article.","name":"Search Helper Extension (Microsoft)","created":"2011-03-31T16:28:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0","minVersion":"1.0","targetApplication":[]}],"id":"2655f230-11f3-fe4c-7c3d-757d37d5f9a5","last_modified":1482945809092},{"guid":"{841468a1-d7f4-4bd3-84e6-bb0f13a06c64}","prefs":[],"schema":1482945112982,"blockID":"i46","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=712369","who":"Users of all versions of Nectar Search Toolbar in Firefox 9.","why":"This add-on causes crashes and other stability issues in Firefox.","name":"Nectar Search Toolbar","created":"2011-12-20T11:38:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"9.0","minVersion":"9.0a1"}]}],"id":"b660dabd-0dc0-a55c-4b86-416080b345d9","last_modified":1482945809069},{"guid":"support@daemon-tools.cc","prefs":[],"schema":1482945112982,"blockID":"i5","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=459850","who":"Users of Daemon Tools Toolbar version 1.0.0.5 and older for all Mozilla applications.","why":"This add-on causes a high volume of crashes.","name":"Daemon Tools Toolbar","created":"2009-02-13T18:39:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.0.5","minVersion":"0","targetApplication":[]}],"id":"8cabafd3-576a-b487-31c8-ab59e0349a0e","last_modified":1482945809045},{"guid":"{a3a5c777-f583-4fef-9380-ab4add1bc2a8}","prefs":[],"schema":1482945112982,"blockID":"i53","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=719605","who":"All users of Firefox with this add-on installed.","why":"This add-on is being offered as an online movie viewer, when it reality it only inserts scripts and ads into known sites.","name":"Peliculas-FLV (malware)","created":"2012-01-19T15:58:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0.3","minVersion":"2.0.3","targetApplication":[]}],"id":"07bc0962-60da-087b-c3ab-f2a6ab84d81c","last_modified":1482945809021},{"guid":"royal@facebook.com","prefs":[],"schema":1482945112982,"blockID":"i64","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=725777","who":"All Firefox users who have installed this add-on.","why":"Malicious add-on posing as a Facebook tool.","name":"Facebook ! (malware)","created":"2012-02-09T13:24:23Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dd1d2623-0d15-c93e-8fbd-ba07b0299a44","last_modified":1482945808997},{"guid":"{28bfb930-7620-11e1-b0c4-0800200c9a66}","prefs":[],"schema":1482945112982,"blockID":"i108","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=766852","who":"All Firefox user who have this add-on installed.","why":"This is malware disguised as an Adobe product. It spams Facebook pages.","name":"Aplicativo (malware)","created":"2012-06-21T09:24:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"908dc4fb-ebc9-cea1-438f-55e4507ba834","last_modified":1482945808973},{"guid":"socialnetworktools@mozilla.doslash.org","prefs":[],"schema":1482945112982,"blockID":"i78","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=739441","who":"All Firefox users who have installed this add-on.","why":"This add-on hijacks the Facebook UI and adds scripts to track users.","name":"Social Network Tools (malware)","created":"2012-03-26T16:46:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1064cd25-3b87-64bb-b0a6-2518ad281574","last_modified":1482945808950},{"guid":"youtubeeing@youtuberie.com","prefs":[],"schema":1482945112982,"blockID":"i98","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759663","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Youtube add-on.","name":"Youtube Video Player (malware)","created":"2012-05-30T09:30:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3484f860-56e1-28e8-5a70-cdcd5ab9d6ee","last_modified":1482945808927},{"guid":"{3a12052a-66ef-49db-8c39-e5b0bd5c83fa}","prefs":[],"schema":1482945112982,"blockID":"i101","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=761874","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware disguised as a Facebook timeline remover.","name":"Timeline Remove (malware)","created":"2012-06-05T18:37:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b01b321b-6628-7166-bd15-52f21a04d8bd","last_modified":1482945808904},{"guid":"pfzPXmnzQRXX6@2iABkVe.com","prefs":[],"schema":1482945112982,"blockID":"i99","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=759950","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware disguised as a Flash Player update.","name":"Flash Player (malware)","created":"2012-05-30T17:10:18Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"29cc4abc-4f52-01f1-eb0b-cad84ba4db13","last_modified":1482945808881},{"guid":"/^(@pluginscribens_firefox|extension@vidscrab.com|firefox@jjj.ee|firefox@shop-reward.de|FxExtPasteNGoHtk@github.lostdj|himanshudotrai@gmail.com|jid0-bigoD0uivzAMmt07zrf3OHqa418@jetpack|jid0-iXbAR01tjT2BsbApyS6XWnjDhy8@jetpack)$/","prefs":[],"schema":1482341309012,"blockID":"i1423","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:21:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a58a2836-e4e7-74b5-c109-fa3d41e9ed56","last_modified":1482343886390},{"guid":"/^(pdftoword@addingapps.com|jid0-EYTXLS0GyfQME5irGbnD4HksnbQ@jetpack|jid1-ZjJ7t75BAcbGCX@jetpack)$/","prefs":[],"schema":1482341309012,"blockID":"i1425","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1325060","who":"All users who have any of the affected versions installed.","why":"A security vulnerability was discovered in old versions of the Add-ons SDK, which is exposed by certain old versions of add-ons. In the case of some add-ons that haven't been updated for a long time, all versions are being blocked.","name":"Various vulnerable add-on versions","created":"2016-12-21T17:23:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"150e639f-c832-63d0-a775-59313b2e1bf9","last_modified":1482343886365},{"guid":"{cc8f597b-0765-404e-a575-82aefbd81daf}","prefs":[],"schema":1480349193877,"blockID":"i380","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866332","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts and performs unwanted actions on behalf of the user.","name":"Update My Browser (malware)","created":"2013-06-19T13:03:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4950d7aa-c602-15f5-a7a2-d844182d5cbd","last_modified":1480349217152},{"guid":"extension@FastFreeConverter.com","prefs":[],"schema":1480349193877,"blockID":"i470","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"649dd933-debf-69b7-020f-496c2c9f99c8","last_modified":1480349217071},{"guid":"59D317DB041748fdB89B47E6F96058F3@jetpack","prefs":[],"schema":1480349193877,"blockID":"i694","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053540","who":"All Firefox users who have this add-ons installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This is a suspicious add-on that appears to be installed without user consent, in violation of the Add-on Guidelines.","name":"JsInjectExtension","created":"2014-08-21T13:46:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"75692bd4-18e5-a9be-7ec3-9327e159ef68","last_modified":1480349217005},{"guid":"/^({bfec236d-e122-4102-864f-f5f19d897f5e}|{3f842035-47f4-4f10-846b-6199b07f09b8}|{92ed4bbd-83f2-4c70-bb4e-f8d3716143fe})$/","prefs":[],"schema":1480349193877,"blockID":"i527","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and uses multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:13:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d68dd97-7965-0a84-8ca7-435aac3c8040","last_modified":1480349216927},{"guid":"support@vide1flash2.com","prefs":[],"schema":1480349193877,"blockID":"i246","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=830159","who":"All Firefox users who have this add-on installed.","why":"This is an add-on that poses as the Adobe Flash Player and runs malicious code in the user's system.","name":"Lastest Adobe Flash Player (malware)","created":"2013-01-14T09:17:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2004fba1-74bf-a072-2a59-6e0ba827b541","last_modified":1480349216871},{"guid":"extension21804@extension21804.com","prefs":[],"schema":1480349193877,"blockID":"i312","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835665","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"Coupon Companion","created":"2013-03-06T14:14:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b2cf1256-dadd-6501-1f4e-25902d408692","last_modified":1480349216827},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i602","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:18:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.8.*","minVersion":"3.15.8","targetApplication":[]}],"id":"b2b4236d-5d4d-82b2-99cd-00ff688badf1","last_modified":1480349216765},{"guid":"nosquint@urandom.ca","prefs":[],"schema":1480349193877,"blockID":"i1232","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1279561","who":"Users on Firefox 47, and higher, using version 2.1.9.1, and earlier, of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"The add-on is breaking the in-built zoom functionality on Firefox 47.","name":"NoSquint","created":"2016-06-10T17:12:55Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.1.9.1-signed.1-signed","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"47"}]}],"id":"30e0a35c-056a-054b-04f3-ade68b83985a","last_modified":1480349216711},{"guid":"{FE1DEEEA-DB6D-44b8-83F0-34FC0F9D1052}","prefs":[],"schema":1480349193877,"blockID":"i364","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867670","who":"All Firefox users who have this add-on installed. Users who want to enable the add-on again can do so in the Add-ons Manager.","why":"This add-on is side-installed with other software, and blocks setting reversions attempted by users who want to recover their settings after they are hijacked by other add-ons.","name":"IB Updater","created":"2013-06-10T16:14:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a59b967c-66ca-7ad9-2dc6-d0ad37ded5fd","last_modified":1480349216652},{"guid":"vpyekkifgv@vpyekkifgv.org","prefs":[],"schema":1480349193877,"blockID":"i352","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=872211","who":"All Firefox users who have this add-on installed.","why":"Uses a deceptive name and injects ads into pages without user consent.","name":"SQLlite Addon (malware)","created":"2013-05-14T13:42:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fd981ab-7ee0-e367-d804-0efe29d63178","last_modified":1480349216614},{"guid":"/^firefox@(albrechto|swiftbrowse|springsmart|storimbo|squirrelweb|betterbrowse|lizardlink|rolimno|browsebeyond|clingclang|weblayers|kasimos|higher-aurum|xaven|bomlabio)\\.(com?|net|org|info|biz)$/","prefs":[],"schema":1480349193877,"blockID":"i549","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937405","who":"All Firefox users who have one or more of these add-ons installed. If you wish to continue using any of these add-ons, they can be enabled in the Add-ons Manager.","why":"A large amount of add-ons developed by Yontoo are known to be silently installed and otherwise violate the Add-on Guidelines.","name":"Yontoo add-ons","created":"2014-01-30T15:08:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a124164-b177-805b-06f7-70a358b37e08","last_modified":1480349216570},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i702","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T10:05:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"1.10","targetApplication":[]}],"id":"60e54f6a-1b10-f889-837f-60a76a98fccc","last_modified":1480349216512},{"guid":"/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i396","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881454","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"PutLockerDownloader and related","created":"2013-06-25T12:48:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e98ba6e3-f2dd-fdee-b106-3e0d2a03cda4","last_modified":1480349216487},{"guid":"my7thfakeid@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i1262","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1295616","who":"Anyone who has this add-on installed.","why":"This add-on is a keylogger that sends the data to a remote server, and goes under the name Real_player.addon.","name":"Remote Keylogger test 0 addon","created":"2016-08-17T10:54:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81b380c0-8092-ea5e-11cd-54c7f563ff5a","last_modified":1480349216460},{"guid":"{f0e59437-6148-4a98-b0a6-60d557ef57f4}","prefs":[],"schema":1480349193877,"blockID":"i304","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845975","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our installation guidelines and is dropped silently into user's profiles.","name":"WhiteSmoke B","created":"2013-02-27T13:10:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0469e643-1a90-f9be-4aad-b347469adcbe","last_modified":1480349216402},{"os":"Darwin,Linux","guid":"firebug@software.joehewitt.com","prefs":[],"schema":1480349193877,"blockID":"i75","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=718831","who":"All Firefox 9 users on Mac OS X or Linux who have Firebug 1.9.0 installed.","why":"Firebug 1.9.0 creates stability problems on Firefox 9, on Mac OS X and Linux. Upgrading to Firefox 10 or later, or upgrading to Firebug 1.9.1 or later fixes this problem.","name":"Firebug","created":"2012-03-21T16:00:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.9.0","minVersion":"1.9.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"9.*","minVersion":"9.0a1"}]}],"id":"a1f9f055-ef34-1412-c39f-35605a70d031","last_modified":1480349216375},{"guid":"xz123@ya456.com","prefs":[],"schema":1480349193877,"blockID":"i486","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-11-15T13:34:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b9825a25-a96c-407e-e656-46a7948e5745","last_modified":1480349215808},{"guid":"{C7AE725D-FA5C-4027-BB4C-787EF9F8248A}","prefs":[],"schema":1480349193877,"blockID":"i424","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=860641","who":"Users of Firefox 23 or later who have RelevantKnowledge 1.0.0.2 or lower.","why":"Old versions of this add-on are causing startup crashes in Firefox 23, currently on the Beta channel. RelevantKnowledge users on Firefox 23 and above should update to version 1.0.0.3 of the add-on.","name":"RelevantKnowledge 1.0.0.2 and lower","created":"2013-07-01T10:45:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.0.2","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"23.0a1"}]}],"id":"c888d167-7970-4b3f-240f-2d8e6f14ded4","last_modified":1480349215779},{"guid":"{5C655500-E712-41e7-9349-CE462F844B19}","prefs":[],"schema":1480349193877,"blockID":"i966","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1175425","who":"All users who have this add-on installed.","why":"This add-on is vulnerable to a cross-site scripting attack, putting users at risk when using it in arbitrary websites.","name":"Quick Translator","created":"2015-07-17T13:42:28Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.1-signed","minVersion":"0","targetApplication":[]}],"id":"f34b00a6-c783-7851-a441-0d80fb1d1031","last_modified":1480349215743},{"guid":"superlrcs@svenyor.net","prefs":[],"schema":1480349193877,"blockID":"i545","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949596","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is in violation of the Add-on Guidelines, using multiple add-on IDs and potentially doing other unwanted activities.","name":"SuperLyrics","created":"2014-01-30T11:52:42Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"002cd4fa-4c2b-e28b-9220-4a520f4d9ec6","last_modified":1480349215672},{"guid":"mbrsepone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i479","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937331","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Lightweight Pack (malware)","created":"2013-11-11T15:42:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0549645e-5f50-5089-1f24-6e7d3bfab8e0","last_modified":1480349215645},{"guid":"/^brasilescape.*\\@facebook\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i453","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=918566","who":"All Firefox users who have these add-ons installed.","why":"This is a group of malicious add-ons that use deceitful names like \"Facebook Video Pack\" or \"Mozilla Service Pack\" and hijack Facebook accounts.","name":"Brasil Escape (malware)","created":"2013-09-20T09:54:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8e6b1176-1794-2117-414e-f0821443f27b","last_modified":1480349215591},{"guid":"foxyproxy-basic@eric.h.jung","prefs":[],"schema":1480349193877,"blockID":"i952","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1183890","who":"All users who have this add-on installed on Thunderbird 38 and above.","why":"This add-on is causing consistent startup crashes on Thunderbird 38 and above.","name":"FoxyProxy Basic for Thunderbird","created":"2015-07-15T09:35:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.5.5","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"},{"guid":"{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}","maxVersion":"*","minVersion":"2.35"}]}],"id":"81658491-feda-2ed3-3c6c-8e60c2b73aee","last_modified":1480349215536},{"guid":"mbroctone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i476","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936590","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks the users' Facebook account.","name":"Mozilla Storage Service (malware)","created":"2013-11-08T15:32:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"92198396-8756-8d09-7f18-a68d29894f71","last_modified":1480349215504},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i616","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:24:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.28.*","minVersion":"3.15.28","targetApplication":[]}],"id":"f11b485f-320e-233c-958b-a63377024fad","last_modified":1480349215479},{"guid":"/^({e9df9360-97f8-4690-afe6-996c80790da4}|{687578b9-7132-4a7a-80e4-30ee31099e03}|{46a3135d-3683-48cf-b94c-82655cbc0e8a}|{49c795c2-604a-4d18-aeb1-b3eba27e5ea2}|{7473b6bd-4691-4744-a82b-7854eb3d70b6}|{96f454ea-9d38-474f-b504-56193e00c1a5})$/","prefs":[],"schema":1480349193877,"blockID":"i494","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=776404","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. It also uses multiple add-on IDs for no apparent reason. This violates our Add-on Guidelines.","name":"uTorrent and related","created":"2013-12-02T14:52:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"485210d0-8e69-3436-536f-5d1deeea4167","last_modified":1480349215454},{"guid":"{EB7508CA-C7B2-46E0-8C04-3E94A035BD49}","prefs":[],"schema":1480349193877,"blockID":"i162","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=799266","who":"All Firefox users who have installed any of these add-ons.","why":"This block covers a number of malicious add-ons that deceive users, using names like \"Mozilla Safe Browsing\" and \"Translate This!\", and claiming they are developed by \"Mozilla Corp.\". They hijack searches and redirects users to pages they didn't intend to go to.\r\n\r\nNote: this block won't be active until bug 799266 is fixed.","name":"Mozilla Safe Browsing and others (Medfos malware)","created":"2012-10-11T12:25:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"07566aa3-4ff9-ac4f-9de9-71c77454b4da","last_modified":1480349215428},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i614","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:23:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.26.*","minVersion":"3.15.26","targetApplication":[]}],"id":"ede541f3-1748-7b33-9bd6-80e2f948e14f","last_modified":1480349215399},{"guid":"/^({976cd962-e0ca-4337-aea7-d93fae63a79c}|{525ba996-1ce4-4677-91c5-9fc4ead2d245}|{91659dab-9117-42d1-a09f-13ec28037717}|{c1211069-1163-4ba8-b8b3-32fc724766be})$/","prefs":[],"schema":1480349193877,"blockID":"i522","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:15:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"580aed26-dc3b-eef8-fa66-a0a402447b7b","last_modified":1480349215360},{"guid":"jid0-O6MIff3eO5dIGf5Tcv8RsJDKxrs@jetpack","prefs":[],"schema":1480349193877,"blockID":"i552","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974041","who":"All Firefox users who have this extension installed.","why":"This extension is malware that attempts to make it impossible for a second extension and itself to be disabled, and also forces the new tab page to have a specific URL.","name":"Extension_Protected (malware)","created":"2014-02-19T15:26:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e53063b4-5702-5b66-c860-d368cba4ccb6","last_modified":1480349215327},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i604","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:18:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.11.*","minVersion":"3.15.10","targetApplication":[]}],"id":"b910f779-f36e-70e1-b17a-8afb75988c03","last_modified":1480349215302},{"guid":"brasilescapefive@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i483","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938473","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Facebook Video Pack (malware)","created":"2013-11-14T09:37:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"85ee7840-f262-ad30-eb91-74b3248fd13d","last_modified":1480349215276},{"guid":"brasilescapeeight@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i482","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938476","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Security Pack (malware)","created":"2013-11-14T09:36:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"457a5722-be90-5a9f-5fa0-4c753e9f324c","last_modified":1480349215249},{"guid":"happylyrics@hpyproductions.net","prefs":[],"schema":1480349193877,"blockID":"i370","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881815","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into Firefox without the users' consent, violating our Add-on Guidelines.","name":"Happy Lyrics","created":"2013-06-11T15:42:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"730e616d-94a7-df0c-d31a-98b7875d60c2","last_modified":1480349215225},{"guid":"search-snacks@search-snacks.com","prefs":[],"schema":1480349193877,"blockID":"i872","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082733","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Search Snacks","created":"2015-03-04T14:37:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7567b06f-98fb-9400-8007-5d0357c345d9","last_modified":1480349215198},{"os":"WINNT","guid":"{ABDE892B-13A8-4d1b-88E6-365A6E755758}","prefs":[],"schema":1480349193877,"blockID":"i107","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=764210","who":"All Firefox users on Windows who have the RealPlayer Browser Record extension installed.","why":"The RealPlayer Browser Record extension is causing significant problems on Flash video sites like YouTube. This block automatically disables the add-on, but users can re-enable it from the Add-ons Manager if necessary.\r\n\r\nThis block shouldn't disable any other RealPlayer plugins, so watching RealPlayer content on the web should be unaffected.\r\n\r\nIf you still have problems playing videos on YouTube or elsewhere, please visit our support site for help.","name":"RealPlayer Browser Record Plugin","created":"2012-06-14T13:54:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"15.0.5","minVersion":"0","targetApplication":[]}],"id":"e3b89e55-b35f-8694-6f0e-f856e57a191d","last_modified":1480349215173},{"guid":"/(\\{7aeae561-714b-45f6-ace3-4a8aed6e227b\\})|(\\{01e86e69-a2f8-48a0-b068-83869bdba3d0\\})|(\\{77f5fe49-12e3-4cf5-abb4-d993a0164d9e\\})/","prefs":[],"schema":1480349193877,"blockID":"i436","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=891606","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow the Add-on Guidelines, changing Firefox default settings and not reverting them on uninstall. If you want to continue using this add-on, it can be enabled in the Add-ons Manager.","name":"Visual Bee","created":"2013-08-09T15:04:44Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ad6dc811-ab95-46fa-4bff-42186c149980","last_modified":1480349215147},{"guid":"amo-validator-bypass@example.com","prefs":[],"schema":1480349193877,"blockID":"i1058","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1227605","who":"All users who install this add-on.","why":"This add-on is a proof of concept of a malicious add-on that bypasses the code validator.","name":" AMO Validator Bypass","created":"2015-11-24T09:03:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"86e38e3e-a729-b5a2-20a8-4738b376eea6","last_modified":1480349214743},{"guid":"6lIy@T.edu","prefs":[],"schema":1480349193877,"blockID":"i852","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128269","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"unIsaless","created":"2015-02-09T15:30:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39798bc2-9c75-f172-148b-13f3ca1dde9b","last_modified":1480349214613},{"guid":"{394DCBA4-1F92-4f8e-8EC9-8D2CB90CB69B}","prefs":[],"schema":1480349193877,"blockID":"i100","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=761339","who":"All Firefox users who have Lightshot 2.5.0 installed.","why":"The Lightshot add-on, version 2.5.0, is causing widespread and frequent crashes in Firefox. Lightshot users are strongly recommended to update to version 2.6.0 as soon as possible.","name":"Lightshot","created":"2012-06-05T09:24:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.5.0","minVersion":"2.5.0","targetApplication":[]}],"id":"57829ea2-5a95-1b6e-953c-7c4a7b3b21ac","last_modified":1480349214568},{"guid":"{a7f2cb14-0472-42a1-915a-8adca2280a2c}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i686","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033809","who":"All users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"HomeTab","created":"2014-08-06T16:35:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"33a8f403-b2c8-cadf-e1ba-40b39edeaf18","last_modified":1480349214537},{"guid":"{CA8C84C6-3918-41b1-BE77-049B2BDD887C}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i862","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131230","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Ebay Shopping Assistant by Spigot","created":"2015-02-26T12:51:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9a9d6da2-90a1-5b71-8b24-96492d57dfd1","last_modified":1480349214479},{"guid":"update@firefox.com","prefs":[],"schema":1480349193877,"blockID":"i374","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=781088","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts.","name":"Premium Update (malware)","created":"2013-06-18T13:58:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bb388413-60ea-c9d6-9a3b-c90df950c319","last_modified":1480349214427},{"guid":"sqlmoz@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i350","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=871610","who":"All Firefox users who have this extension installed.","why":"This extension is malware posing as Mozilla software. It hijacks Facebook accounts and spams other Facebook users.","name":"Mozilla Service Pack (malware)","created":"2013-05-13T09:43:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"715082e8-7a30-b27b-51aa-186c38e078f6","last_modified":1480349214360},{"guid":"iobitapps@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i562","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=948695","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is installed silently and changes users settings without reverting them, in violation of the Add-on Guidelines.","name":"IObit Apps Toolbar","created":"2014-02-27T10:00:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be9a54f6-20c1-7dee-3aea-300b336b2ae5","last_modified":1480349214299},{"guid":"{9e09ac65-43c0-4b9d-970f-11e2e9616c55}","prefs":[],"schema":1480349193877,"blockID":"i376","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=857847","who":"All Firefox users who have installed this add-on.","why":"This add-on is malware that hijacks Facebook accounts and posts content on it.","name":"The Social Networks (malware)","created":"2013-06-18T14:16:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"753638b4-65ca-6d71-f1f5-ce32ba2edf3b","last_modified":1480349214246},{"guid":"mozillahmpg@mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i140","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=791867","who":"All Firefox users who have installed this add-on.","why":"This is a malicious add-on that tries to monetize on its users by embedding unauthorized affiliate codes on shopping websites, and sometimes redirecting users to alternate sites that could be malicious in nature.","name":"Google YouTube HD Player (malware)","created":"2012-09-17T16:04:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98150e2e-cb45-1fee-8458-28d3602ec2ec","last_modified":1480349214216},{"guid":"astrovia@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i489","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=942699","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Facebook Security Service (malware)","created":"2013-11-25T12:40:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6f365ff4-e48f-8a06-d19d-55e19fba81f4","last_modified":1480349214157},{"guid":"{bbea93c6-64a3-4a5a-854a-9cc61c8d309e}","prefs":[],"schema":1480349193877,"blockID":"i1126","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that disables various security checks in Firefox.","name":"Tab Extension (malware)","created":"2016-02-29T21:58:10Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5acb9dcc-59d4-46d1-2a11-1194c4948239","last_modified":1480349214066},{"guid":"ffxtlbr@iminent.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i628","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866943","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using them can enable them in the Add-ons Manager.","why":"These add-ons have been silently installed repeatedly, and change settings without user consent, in violation of the Add-on Guidelines.","name":"Iminent Minibar","created":"2014-06-26T15:47:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4387ad94-8500-d74d-68e3-20564a9aac9e","last_modified":1480349214036},{"guid":"{28387537-e3f9-4ed7-860c-11e69af4a8a0}","prefs":[],"schema":1480349193877,"blockID":"i40","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=665775","who":"Users of MediaBar versions 4.3.1.00 and below in all versions of Firefox.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"MediaBar (2)","created":"2011-07-19T10:19:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.3.1.00","minVersion":"0.1","targetApplication":[]}],"id":"ff95664b-93e4-aa73-ac20-5ffb7c87d8b7","last_modified":1480349214002},{"guid":"{41e5ef7a-171d-4ab5-8351-951c65a29908}","prefs":[],"schema":1480349193877,"blockID":"i784","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"HelpSiteExpert","created":"2014-11-14T14:37:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0c05a0bb-30b4-979e-33a7-9f3955eba17d","last_modified":1480349213962},{"guid":"/^({2d7886a0-85bb-4bf2-b684-ba92b4b21d23}|{2fab2e94-d6f9-42de-8839-3510cef6424b}|{c02397f7-75b0-446e-a8fa-6ef70cfbf12b}|{8b337819-d1e8-48d3-8178-168ae8c99c36}|firefox@neurowise.info|firefox@allgenius.info)$/","prefs":[],"schema":1480349193877,"blockID":"i762","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082599","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"These add-ons are silently installed into users' systems, in violation of the Add-on Guidelines.","name":"SaveSense, neurowise, allgenius","created":"2014-10-17T16:58:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c5439f55-ace5-ad73-1270-017c0ba7b2ce","last_modified":1480349213913},{"guid":"{462be121-2b54-4218-bf00-b9bf8135b23f}","prefs":[],"schema":1480349193877,"blockID":"i226","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812303","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and doesn't do much more than changing the users' settings, without reverting them on removal.","name":"WhiteSmoke","created":"2012-11-29T16:27:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"994c6084-e864-0e4e-ac91-455083ee46c7","last_modified":1480349213879},{"guid":"firefox@browsefox.com","prefs":[],"schema":1480349193877,"blockID":"i546","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936244","who":"All Firefox users who have this add-on installed. If you want to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed, in violation of the Add-on Guidelines.","name":"BrowseFox","created":"2014-01-30T12:26:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"407d8c84-8939-cd28-b284-9b680e529bf6","last_modified":1480349213853},{"guid":"{6926c7f7-6006-42d1-b046-eba1b3010315}","prefs":[],"schema":1480349193877,"blockID":"i382","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844956","who":"All Firefox users who have this add-on installed. Those who wish to continue using it can enable it again in the Add-ons Manager.","why":"This add-on is silently installed, bypassing the Firefox opt-in screen and violating our Add-on Guidelines.","name":"appbario7","created":"2013-06-25T12:05:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2367bd94-2bdd-c615-de89-023ba071a443","last_modified":1480349213825},{"guid":"faststartff@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i866","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131217","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Fast Start","created":"2015-02-26T13:12:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9e730bca-c7d1-da82-64f6-c74de216cb7d","last_modified":1480349213799},{"guid":"05dd836e-2cbd-4204-9ff3-2f8a8665967d@a8876730-fb0c-4057-a2fc-f9c09d438e81.com","prefs":[],"schema":1480349193877,"blockID":"i468","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935135","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be part of a Trojan software package.","name":"Trojan.DownLoader9.50268 (malware)","created":"2013-11-07T14:43:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2fd53d9b-7096-f1fb-fbcb-2b40a6193894","last_modified":1480349213774},{"guid":"jid1-0xtMKhXFEs4jIg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i586","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011286","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware installed without user consent.","name":"ep (malware)","created":"2014-06-03T15:50:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"50ca2179-83ab-1817-163d-39ed2a9fbd28","last_modified":1480349213717},{"guid":"/^({16e193c8-1706-40bf-b6f3-91403a9a22be}|{284fed43-2e13-4afe-8aeb-50827d510e20}|{5e3cc5d8-ed11-4bed-bc47-35b4c4bc1033}|{7429e64a-1fd4-4112-a186-2b5630816b91}|{8c9980d7-0f09-4459-9197-99b3e559660c}|{8f1d9545-0bb9-4583-bb3c-5e1ac1e2920c})$/","prefs":[],"schema":1480349193877,"blockID":"i517","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:54:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e88a28ab-5569-f06d-b0e2-15c51bb2a4b7","last_modified":1480349213344},{"guid":"safebrowse@safebrowse.co","prefs":[],"schema":1480349193877,"blockID":"i782","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1097696","who":"All Firefox users who have this add-on installed.","why":"This add-on loads scripts with malicious code that appears intended to steal usernames, passwords, and other private information.","name":"SafeBrowse","created":"2014-11-12T14:20:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"edd81c91-383b-f041-d8f6-d0b9a90230bd","last_modified":1480349213319},{"guid":"{af95cc15-3b9b-45ae-8d9b-98d08eda3111}","prefs":[],"schema":1480349193877,"blockID":"i492","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945126","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook (malware)","created":"2013-12-02T12:45:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7064e9e2-fba4-7b57-86d7-6f4afbf6f560","last_modified":1480349213294},{"guid":"{84a93d51-b7a9-431e-8ff8-d60e5d7f5df1}","prefs":[],"schema":1480349193877,"blockID":"i744","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080817","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be silently installed into users' systems, and changes settings without consent, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-10-17T15:47:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dbc7ef8b-2c48-5dae-73a0-f87288c669f0","last_modified":1480349213264},{"guid":"{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}","prefs":[],"schema":1480349193877,"blockID":"i918","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:58:16Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"7f2a68f3-aa8a-ae41-1e48-d1f8f63d53c7","last_modified":1480349213231},{"guid":"831778-poidjao88DASfsAnindsd@jetpack","prefs":[],"schema":1480349193877,"blockID":"i972","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190962","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video patch (malware)","created":"2015-08-04T15:18:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39471221-6926-e11b-175a-b28424d49bf6","last_modified":1480349213194},{"guid":"lbmsrvfvxcblvpane@lpaezhjez.org","prefs":[],"schema":1480349193877,"blockID":"i342","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=863385","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. It also appears to install itself both locally and globally, producing a confusing uninstall experience.","name":"RapidFinda","created":"2013-05-06T16:18:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98fb4536-07a4-d03a-f7c5-945acecc8203","last_modified":1480349213128},{"guid":"{babb9931-ad56-444c-b935-38bffe18ad26}","prefs":[],"schema":1480349193877,"blockID":"i499","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946086","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook Credits (malware)","created":"2013-12-04T15:22:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be1d19fa-1662-322a-13e6-5fa5474f33a7","last_modified":1480349213100},{"guid":"{18d5a8fe-5428-485b-968f-b97b05a92b54}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i802","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda Search Addon","created":"2014-12-15T10:52:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bc846147-cdc1-141f-5846-b705c48bd6ed","last_modified":1480349213074},{"guid":"{b6ef1336-69bb-45b6-8cba-e578fc0e4433}","prefs":[],"schema":1480349193877,"blockID":"i780","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Power-SW","created":"2014-11-12T14:00:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3b080157-2900-d071-60fe-52b0aa376cf0","last_modified":1480349213024},{"guid":"info@wxdownloadmanager.com","prefs":[],"schema":1480349193877,"blockID":"i196","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec (malware)","created":"2012-11-05T09:24:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b62597d0-d2cb-d597-7358-5143a1d13658","last_modified":1480349212999},{"os":"WINNT","guid":"{C3949AC2-4B17-43ee-B4F1-D26B9D42404D}","prefs":[],"schema":1480349193877,"blockID":"i111","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=771802","who":"All Firefox users on Windows who have the RealPlayer Browser Record extension installed.","why":"The RealPlayer Browser Record extension is causing significant problems on Flash video sites like YouTube. This block automatically disables the add-on, but users can re-enable it from the Add-ons Manager if necessary.\r\n\r\nThis block shouldn't disable any other RealPlayer plugins, so watching RealPlayer content on the web should be unaffected.\r\n\r\nIf you still have problems playing videos on YouTube or elsewhere, please visit our support site for help.","name":"RealPlayer Browser Record Plugin","created":"2012-07-10T15:28:16Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"15.0.5","minVersion":"0","targetApplication":[]}],"id":"d3f96257-7635-555f-ef48-34d426322992","last_modified":1480349212971},{"guid":"l@AdLJ7uz.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i728","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines","name":"GGoSavee","created":"2014-10-16T16:34:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e6bfa340-7d8a-1627-5cdf-40c0c4982e9d","last_modified":1480349212911},{"guid":"{6b2a75c8-6e2e-4267-b955-43e25b54e575}","prefs":[],"schema":1480349193877,"blockID":"i698","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1052611","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"BrowserShield","created":"2014-08-21T15:46:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"492e4e43-f89f-da58-9c09-d99528ee9ca9","last_modified":1480349212871},{"guid":"/^({65f9f6b7-2dae-46fc-bfaf-f88e4af1beca}|{9ed31f84-c8b3-4926-b950-dff74047ff79}|{0134af61-7a0c-4649-aeca-90d776060cb3}|{02edb56b-9b33-435b-b7df-b2843273a694}|{da51d4f6-3e7e-4ef8-b400-9198e0874606}|{b24577db-155e-4077-bb37-3fdd3c302bb5})$/","prefs":[],"schema":1480349193877,"blockID":"i525","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:11:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"78562d79-9a64-c259-fb63-ce24e29bb141","last_modified":1480349212839},{"guid":"adsremoval@adsremoval.net","prefs":[],"schema":1480349193877,"blockID":"i560","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=962793","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes various user settings, in violation of the Add-on Guidelines.","name":"Ad Removal","created":"2014-02-27T09:57:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4d150ad4-dc22-9790-07a9-36e0a23f857f","last_modified":1480349212798},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i445","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=911966","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that imitates a popular video downloader extension, and attempts to hijack Facebook accounts. The add-on available in the add-ons site is safe to use.","name":"YouTube Enhancer Plus (malware)","created":"2013-09-04T16:53:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.7.0","minVersion":"208.7.0","targetApplication":[]}],"id":"41d75d3f-a57e-d5ad-b95b-22f5fa010b4e","last_modified":1480349212747},{"guid":"suchpony@suchpony.de","prefs":[],"schema":1480349193877,"blockID":"i1264","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have version 1.6.7 or less of this add-on installed.","why":"Old versions of this add-on contained code from YouTube Unblocker, which was originally blocked due to malicious activity. Version 1.6.8 is now okay.","name":"Suchpony (pre 1.6.8)","created":"2016-08-24T10:48:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.6.7","minVersion":"0","targetApplication":[]}],"id":"1bbf00f3-53b5-3777-43c7-0a0b11f9c433","last_modified":1480349212719},{"guid":"{336D0C35-8A85-403a-B9D2-65C292C39087}","prefs":[],"schema":1480349193877,"blockID":"i224","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812292","who":"All Firefox users who have this add-on installed.","why":"This add-on is side-installed with other software, and blocks setting reversions attempted by users who want to recover their settings after they are hijacked by other add-ons.","name":"IB Updater","created":"2012-11-29T16:22:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c87666e6-ec9a-2f1e-ad03-a722d2fa2a25","last_modified":1480349212655},{"guid":"G4Ce4@w.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i718","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and changes settings without consent, in violation of the Add-on Guidelines.","name":"YoutUbeAdBlaocke","created":"2014-10-02T12:21:22Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e1e9322-93e9-4ce1-41f5-46ad4ef1471b","last_modified":1480349212277},{"guid":"extension@Fast_Free_Converter.com","prefs":[],"schema":1480349193877,"blockID":"i533","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949597","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing it.","name":"FastFreeConverter","created":"2013-12-20T15:04:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"726f5645-c0bf-66dc-a97a-d072b46e63e7","last_modified":1480349212247},{"guid":"@stopad","prefs":[],"schema":1480349193877,"blockID":"i1266","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1298780","who":"Users who have version 0.0.4 and earlier of the add-on installed.","why":"Stop Ads sends each visited url to a third party server which is not necessary for the add-on to work or disclosed in a privacy policy or user opt-in. Versions 0.0.4 and earlier are affected.","name":"Stop Ads Addon","created":"2016-08-30T12:24:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.0.4","minVersion":"0","targetApplication":[]}],"id":"3d1893dd-2092-d1f7-03f3-9629b7d7139e","last_modified":1480349212214},{"guid":"703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com","prefs":[],"schema":1480349193877,"blockID":"i519","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:57:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a27d0f9f-7708-3d5f-82e1-e3f29e6098a0","last_modified":1480349212183},{"guid":"imbaty@taringamp3.com","prefs":[],"schema":1480349193877,"blockID":"i662","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that attempts to hide itself by impersonating the Adobe Flash plugin.","name":"Taringa MP3 / Adobe Flash","created":"2014-07-10T15:39:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f43859d4-46b7-c028-4738-d40a73ddad7b","last_modified":1480349212157},{"guid":"{13c9f1f9-2322-4d5c-81df-6d4bf8476ba4}","prefs":[],"schema":1480349193877,"blockID":"i348","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867359","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. It also fails to revert settings changes on removal.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"mywebsearch","created":"2013-05-08T15:55:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"372cf3df-0810-85d8-b5d7-faffff309a11","last_modified":1480349212102},{"guid":"{a6e67e6f-8615-4fe0-a599-34a73fc3fba5}","prefs":[],"schema":1480349193877,"blockID":"i346","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867333","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. Also, it doesn't reset its settings changes on uninstall.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Startnow","created":"2013-05-06T17:06:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1caf911c-ff2f-b0f6-0d32-29ef74be81bb","last_modified":1480349212077},{"guid":"garg_sms@yahoo.in","prefs":[],"schema":1480349193877,"blockID":"i652","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Save My YouTube Day! extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Save My YouTube Day!, version 67.9","created":"2014-07-10T15:17:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"67.9","minVersion":"67.9","targetApplication":[]}],"id":"e50c0189-a7cd-774d-702b-62eade1bf18e","last_modified":1480349212044},{"guid":"9518042e-7ad6-4dac-b377-056e28d00c8f@f1cc0a13-4df1-4d66-938f-088db8838882.com","prefs":[],"schema":1480349193877,"blockID":"i308","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=846455","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed, bypassing our third-party opt-in screen, in violation of our Add-on Guidelines.","name":"Solid Savings","created":"2013-02-28T13:48:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"df25ee07-74d4-ccd9-dbbe-7eb053015144","last_modified":1480349212020},{"guid":"jufa098j-LKooapd9jasJ9jliJsd@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1000","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201163","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Secure Video (malware)","created":"2015-09-07T14:00:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c3a98025-0f4e-3bb4-b475-97329e7b1426","last_modified":1480349211979},{"guid":"{46eddf51-a4f6-4476-8d6c-31c5187b2a2f}","prefs":[],"schema":1480349193877,"blockID":"i750","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963788","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Slick Savings","created":"2014-10-17T16:17:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b4ef650-e1ad-d55f-c420-4f26dbb4139c","last_modified":1480349211953},{"guid":"{DAC3F861-B30D-40dd-9166-F4E75327FAC7}","prefs":[],"schema":1480349193877,"blockID":"i924","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:28:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"be57998b-9e4d-1040-e6bb-ed9de056338d","last_modified":1480349211896},{"guid":"JMLv@njMaHh.org","prefs":[],"schema":1480349193877,"blockID":"i790","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1103516","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"YouttubeAdBlocke","created":"2014-11-24T14:14:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"070d5747-137d-8500-8713-cfc6437558a3","last_modified":1480349211841},{"guid":"istart_ffnt@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i888","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152553","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on appears to be malware, being silently installed and hijacking user settings, in violation of the Add-on Guidelines.","name":"Istart","created":"2015-04-10T16:27:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32fad759-38d9-dad9-2295-e44cc6887040","last_modified":1480349211785},{"guid":"gystqfr@ylgga.com","prefs":[],"schema":1480349193877,"blockID":"i449","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=912742","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It is installed bypassing the Firefox opt-in screen, and manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Define Ext","created":"2013-09-13T16:19:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fe8f509-c530-777b-dccf-d10d58ae78cf","last_modified":1480349211748},{"guid":"e9d197d59f2f45f382b1aa5c14d82@8706aaed9b904554b5cb7984e9.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i844","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128324","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and attempts to change user settings like the home page and default search, in violation of the Add-on Guidelines.","name":"Sense","created":"2015-02-06T15:01:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8f8695c-a356-a1d6-9291-502b377c63c2","last_modified":1480349211713},{"guid":"{184AA5E6-741D-464a-820E-94B3ABC2F3B4}","prefs":[],"schema":1480349193877,"blockID":"i968","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1164243","who":"All users who have this add-on installed.","why":"This is a malicious add-on that poses as a Java extension.","name":"Java String Helper (malware)","created":"2015-08-04T09:41:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fac1d2cb-eed7-fcef-5d5a-43c556371bd7","last_modified":1480349211687},{"guid":"7d51fb17-b199-4d8f-894e-decaff4fc36a@a298838b-7f50-4c7c-9277-df6abbd42a0c.com","prefs":[],"schema":1480349193877,"blockID":"i455","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=919792","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts and posts spam to the users' friends.","name":"Video Console (malware)","created":"2013-09-25T10:28:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dd4d2e17-4ce6-36b0-3035-93e9cc5846d4","last_modified":1480349211660},{"guid":"prositez@prz.com","prefs":[],"schema":1480349193877,"blockID":"i764","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ProfSitez","created":"2014-10-29T16:43:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"684ad4fd-2cbd-ce2a-34cd-bc66b20ac8af","last_modified":1480349211628},{"guid":"/^toolbar[0-9]*@findwide\\.com$/","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i874","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1082758","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.\r\n","name":"FindWide Toolbars","created":"2015-03-04T14:54:10Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a317ad9f-af4d-e086-4afd-cd5eead1ed62","last_modified":1480349211601},{"guid":"{25D77636-38B1-1260-887C-2D4AFA92D6A4}","prefs":[],"schema":1480349193877,"blockID":"i536","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=959279","who":"All Firefox users who have this extension installed.","why":"This is a malicious extension that is installed alongside a trojan. It hijacks searches on selected sites.","name":"Microsoft DirectInput Object (malware)","created":"2014-01-13T10:36:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cd174588-940e-f5b3-12ea-896c957bd4b3","last_modified":1480349211555},{"guid":"fdm_ffext@freedownloadmanager.org","prefs":[],"schema":1480349193877,"blockID":"i216","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=789700","who":"All Firefox users who have installed version 1.5.7.5 of the Free Download Manager extension.","why":"Version 1.5.7.5 of the Free Download Manager extension is causing frequent crashes in recent versions of Firefox. Version 1.5.7.6 corrects this problem, but it is currently not available on addons.mozilla.org. We recommend all users to update to the new version once it becomes available.","name":"Free Download Manager","created":"2012-11-27T12:47:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.5.7.5","minVersion":"1.5.7.5","targetApplication":[]}],"id":"736417a2-6161-9973-991a-aff566314733","last_modified":1480349211163},{"guid":"{badea1ae-72ed-4f6a-8c37-4db9a4ac7bc9}","prefs":[],"schema":1480349193877,"blockID":"i543","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963809","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is apparently malware that is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Address Bar Search","created":"2014-01-28T14:28:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8c1dd68e-7df6-0c37-2f41-107745a7be54","last_modified":1480349211119},{"guid":"addon@gemaoff","prefs":[],"schema":1480349193877,"blockID":"i1230","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"These add-ons are copies of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker (addon@gemaoff)","created":"2016-06-08T16:15:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6bc49e9f-322f-9952-15a6-0a723a61c2d9","last_modified":1480349211044},{"guid":"{d87d56b2-1379-49f4-b081-af2850c79d8e}","prefs":[],"schema":1480349193877,"blockID":"i726","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080835","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Xplorer Lite","created":"2014-10-13T16:01:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7b0895b4-dd4f-1c91-f4e3-31afdbdf3178","last_modified":1480349211007},{"guid":"OKitSpace@OKitSpace.es","prefs":[],"schema":1480349193877,"blockID":"i469","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:35:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6a11aa68-0dae-5524-cc96-a5053a31c466","last_modified":1480349210982},{"guid":"{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}","prefs":[],"schema":1480349193877,"blockID":"i808","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Better Web","created":"2014-12-19T09:36:52Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0413d46b-8205-d9e0-65df-4caa3e6355c4","last_modified":1480349210956},{"guid":"lightningnewtab@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i554","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974041","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed in Firefox and includes a companion extension that also performs malicious actions.","name":"Lightning SpeedDial","created":"2014-02-19T15:28:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"875513e1-e6b1-a383-2ec5-eb4deb87eafc","last_modified":1480349210931},{"guid":"/^ext@bettersurfplus/","prefs":[],"schema":1480349193877,"blockID":"i506","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-12-10T15:10:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b4da06d2-a0fd-09b6-aadb-7e3b29c3be3a","last_modified":1480349210905},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i706","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T14:50:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.6.160","minVersion":"1.6.160","targetApplication":[]}],"id":"bb2b2114-f8e7-511d-04dc-abc8366712cc","last_modified":1480349210859},{"guid":"CortonExt@ext.com","prefs":[],"schema":1480349193877,"blockID":"i336","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=864551","who":"All Firefox users who have this add-on installed.","why":"This add-on is reported to be installed without user consent, with a non-descriptive name, and ties a number of browser features to Amazon URLs, probably monetizing on affiliate codes.","name":"CortonExt","created":"2013-04-22T16:10:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a5bdd05d-eb4c-ce34-9909-a677b4322384","last_modified":1480349210805},{"guid":"1chtw@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i430","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=901770","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that uses a deceptive name and hijacks social networks.","name":" Mozilla Service Pack (malware)","created":"2013-08-05T16:42:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bf1e31c7-ba50-1075-29ae-47368ac1d6de","last_modified":1480349210773},{"guid":"lrcsTube@hansanddeta.com","prefs":[],"schema":1480349193877,"blockID":"i344","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866944","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"LyricsTube","created":"2013-05-06T16:44:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"424b9f39-d028-b1fb-d011-d8ffbbd20fe9","last_modified":1480349210718},{"guid":"{341f4dac-1966-47ff-aacf-0ce175f1498a}","prefs":[],"schema":1480349193877,"blockID":"i356","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=868129","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"MyFreeGames","created":"2013-05-23T14:45:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"560e08b1-3471-ad34-8ca9-463f5ca5328c","last_modified":1480349210665},{"guid":"/^({d6e79525-4524-4707-9b97-1d70df8e7e59}|{ddb4644d-1a37-4e6d-8b6e-8e35e2a8ea6c}|{e55007f4-80c5-418e-ac33-10c4d60db01e}|{e77d8ca6-3a60-4ae9-8461-53b22fa3125b}|{e89a62b7-248e-492f-9715-43bf8c507a2f}|{5ce3e0cb-aa83-45cb-a7da-a2684f05b8f3})$/","prefs":[],"schema":1480349193877,"blockID":"i518","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947509","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing the add-on, and using multiple add-on IDs.","name":"Re-markit","created":"2013-12-20T12:56:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"145b0f22-501e-39eb-371e-ec8342a5add9","last_modified":1480349210606},{"guid":"{72b98dbc-939a-4e0e-b5a9-9fdbf75963ef}","prefs":[],"schema":1480349193877,"blockID":"i772","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"SitezExpert","created":"2014-10-31T16:15:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"386cb2c9-e674-ce2e-345f-d30a785f90c5","last_modified":1480349210536},{"guid":"hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack","prefs":[],"schema":1480349193877,"blockID":"i970","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190963","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video fix (malware)","created":"2015-08-04T15:15:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3ca577d8-3685-4ba9-363b-5b2d8d8dd608","last_modified":1480349210477},{"guid":"{7e8a1050-cf67-4575-92df-dcc60e7d952d}","prefs":[],"schema":1480349193877,"blockID":"i478","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935796","who":"All Firefox users who have this add-on installed.","why":"This add-on violates the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"SweetPacks","created":"2013-11-08T15:42:28Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1519eb45-fcaa-b531-490d-fe366490ed45","last_modified":1480349210416},{"guid":"/^({66b103a7-d772-4fcd-ace4-16f79a9056e0}|{6926c7f7-6006-42d1-b046-eba1b3010315}|{72cabc40-64b2-46ed-8648-26d831761150}|{73ee2cf2-7b76-4c49-b659-c3d8cf30825d}|{ca6446a5-73d5-4c35-8aa1-c71dc1024a18}|{5373a31d-9410-45e2-b299-4f61428f0be4})$/","prefs":[],"schema":1480349193877,"blockID":"i521","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:14:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"983cb7fe-e0b4-6a2e-f174-d2670876b2cd","last_modified":1480349210351},{"guid":"{dd6b651f-dfb9-4142-b0bd-09912ad22674}","prefs":[],"schema":1480349193877,"blockID":"i400","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"975d2126-f727-f5b9-ca01-b83345b80c56","last_modified":1480349210301},{"guid":"25p@9eAkaLq.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i730","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines\r\n","name":"YYOutoubeAdBlocke","created":"2014-10-16T16:35:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5a0c5818-693f-43ae-f85a-c6928d9c2cc4","last_modified":1480349210275},{"os":"Darwin","guid":"thunder@xunlei.com","prefs":[],"schema":1480349193877,"blockID":"i568","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=988490","who":"All Firefox users who have versions 2.0.6 or lower of the Thunder add-on installed on Mac OS.","why":"Versions 2.0.6 and lower of the Thunder add-on are causing startup crashes on Mac OS.","name":"Thunder, 2.0.6 and lower","created":"2014-03-28T15:48:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.0.6","minVersion":"0","targetApplication":[]}],"id":"cee484f6-2d5d-f708-88be-cd12d825a79a","last_modified":1480349210242},{"guid":"tmbepff@trendmicro.com","prefs":[],"schema":1480349193877,"blockID":"i1222","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1275245","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"Add-on is causing a high-frequency crash in Firefox","name":"Trend Micro BEP 9.1.0.1035 and lower","created":"2016-05-24T12:10:34Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.1.0.1035","minVersion":"0","targetApplication":[]}],"id":"8045c799-486a-927c-b972-b9da1c2dab2f","last_modified":1480349209818},{"guid":"pricepeep@getpricepeep.com","prefs":[],"schema":1480349193877,"blockID":"i220","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=811433","who":"All Firefox users who have Pricepeed below 2.1.0.20 installed.","why":"Versions older than 2.1.0.20 of the PricePeep add-on were silently side-installed with other software, injecting advertisements in Firefox. Versions 2.1.0.20 and above don't have the install problems are not blocked.","name":"PricePeep","created":"2012-11-29T16:18:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.1.0.19.99","minVersion":"0","targetApplication":[]}],"id":"227b9a8d-c18d-239c-135e-d79e614fe392","last_modified":1480349209794},{"guid":"ytd@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i360","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845969","who":"All Firefox users who have this add-on installed. Users who want to enable the add-on again can do so in the Add-ons Manager tab.","why":"The installer that includes this add-on performs Firefox settings changes separately from the add-on install, making it very difficult to opt-out to these changes.","name":"YouTube Downloader","created":"2013-06-06T12:29:13Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"63669524-93fe-4823-95ba-37cf6cbd4914","last_modified":1480349209770},{"guid":"hoverst@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i498","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946029","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Adobe Flash Player (malware)","created":"2013-12-04T15:17:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2b25ba3e-45db-0e6c-965a-3acda1a44117","last_modified":1480349209745},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i606","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:20:07Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.13.*","minVersion":"3.15.13","targetApplication":[]}],"id":"c3d88e22-386a-da3b-8aba-3cb526e08053","last_modified":1480349209713},{"guid":"advance@windowsclient.com","prefs":[],"schema":1480349193877,"blockID":"i508","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950773","who":"All Firefox users who have this add-on installed.","why":"This is not the Microsoft .NET Framework Assistant created and distributed by Microsoft. It is a malicious extension that is distributed under the same name to trick users into installing it, and turns users into a botnet that conducts SQL injection attacks on visited websites.","name":"Microsoft .NET Framework Assistant (malware)","created":"2013-12-16T10:15:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e5d30a74-732e-c3fa-f13b-097ee28d4b27","last_modified":1480349209674},{"guid":"{5eeb83d0-96ea-4249-942c-beead6847053}","prefs":[],"schema":1480349193877,"blockID":"i756","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080846","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"SmarterPower","created":"2014-10-17T16:30:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e101dbc0-190c-f6d8-e168-0c1380581cc9","last_modified":1480349209625},{"guid":"/^({7e8a1050-cf67-4575-92df-dcc60e7d952d}|{b3420a9c-a397-4409-b90d-bcf22da1a08a}|{eca6641f-2176-42ba-bdbe-f3e327f8e0af}|{707dca12-3f99-4d94-afea-06dcc0ae0108}|{aea20431-87fc-40be-bc5b-18066fe2819c}|{30ee6676-1ba6-455a-a7e8-298fa863a546})$/","prefs":[],"schema":1480349193877,"blockID":"i523","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947481","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"SweetPacks","created":"2013-12-20T13:42:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a3a6bc8e-46a1-b3d5-1b20-58b90ba099c3","last_modified":1480349209559},{"guid":"{e0352044-1439-48ba-99b6-b05ed1a4d2de}","prefs":[],"schema":1480349193877,"blockID":"i710","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Site Counselor","created":"2014-09-30T15:28:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b8fedf07-dcaf-f0e3-b42b-32db75c4c304","last_modified":1480349209491},{"guid":"{bee6eb20-01e0-ebd1-da83-080329fb9a3a}","prefs":[],"schema":1480349193877,"blockID":"i642","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Flash and Video Download extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Flash and Video Download, between 40.10.1 and 44.10.1","created":"2014-07-10T15:02:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"44.10.1","minVersion":"40.10.1","targetApplication":[]}],"id":"16db0c85-02ec-4f7c-24a3-a504fbce902d","last_modified":1480349209443},{"guid":"addlyrics@addlyrics.net","prefs":[],"schema":1480349193877,"blockID":"i426","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=891605","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Add Lyrics","created":"2013-07-09T15:25:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81678e9e-ebf0-47d6-e409-085c25e67c7e","last_modified":1480349209383},{"guid":"{7b1bf0b6-a1b9-42b0-b75d-252036438bdc}","prefs":[],"schema":1480349193877,"blockID":"i638","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036137","who":"All Firefox users who have this version of the add-on installed.","why":"Versions 27.8 and 27.9 of the YouTube High Definition extension weren't developed by the original developer, and are likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube High Definition 27.8 and 27.9","created":"2014-07-08T16:07:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"27.9","minVersion":"27.8","targetApplication":[]}],"id":"ffdc8ba0-d548-dc5b-d2fd-79a20837124b","last_modified":1480349209260},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i610","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:21:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.22.*","minVersion":"3.15.22","targetApplication":[]}],"id":"935dfec3-d017-5660-db5b-94ae7cea6e5f","last_modified":1480349209128},{"guid":"info@allpremiumplay.info","prefs":[],"schema":1480349193877,"blockID":"i163","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec-C (malware)","created":"2012-10-29T16:40:07Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6afbf9b8-ae3a-6a48-0f6c-7a3e065ec043","last_modified":1480349209076},{"guid":"now.msn.com@services.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i490","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=926378","who":"All Firefox users who have this add-on installed.","why":"As part of their ongoing work to fine-tune their editorial mix, msnNOW has decided that msnNOW will stop publishing on Dec. 3, 2013. Rather than having a single home for trending content, they will continue integrating that material throughout all MSN channels. A big thank you to everyone who followed msnNOW stories using the Firefox sidebar","name":"MSNNow (discontinued social provider)","created":"2013-11-27T08:06:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"de7d699d-016d-d973-5e39-52568de6ffde","last_modified":1480349209021},{"guid":"fftoolbar2014@etech.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i858","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131078","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and changes users' settings, in violation of the Add-on Guidelines.","name":"FF Toolbar","created":"2015-02-11T15:32:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6877bf40-9e45-7017-4dac-14d09e7f0ef6","last_modified":1480349208988},{"guid":"mbrnovone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i477","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=936249","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Mozilla Security Service (malware)","created":"2013-11-08T15:35:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"758c2503-766d-a2f5-4c58-7cea93acfe05","last_modified":1480349208962},{"guid":"{739df940-c5ee-4bab-9d7e-270894ae687a}","prefs":[],"schema":1480349193877,"blockID":"i530","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949558","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"WhiteSmoke New","created":"2013-12-20T14:49:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8097aa6-3009-6dfc-59df-353ba6b1142b","last_modified":1480349208933},{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","prefs":[],"schema":1480349193877,"blockID":"i115","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=779014","who":"All Firefox users who have this add-on installed.","why":"This extension is malware that is installed under false pretenses, and it conducts attacks against certain video websites.","name":"Adobe Flash Player (malware)","created":"2012-08-01T13:53:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aef9312d-5f2e-a44d-464d-6113394148e3","last_modified":1480349208904},{"guid":"g99hiaoekjoasiijdkoleabsy278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1022","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208708","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"WatchIt (malware)","created":"2015-09-28T15:23:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"25e057ea-f500-67df-d078-ec3f37f99036","last_modified":1480349208877},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i636","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033120","who":"All Firefox users who have this version of the add-on installed.","why":"Version 199.7.0 of the YoutubeEnhancer extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YoutubeEnhancer - Firefox","created":"2014-07-08T15:58:12Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"199.7.0","minVersion":"199.7.0","targetApplication":[]}],"id":"204a074b-da87-2784-f15b-43a9ea9a6b36","last_modified":1480349208851},{"guid":"extacylife@a.com","prefs":[],"schema":1480349193877,"blockID":"i505","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947741","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-09T15:08:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5acadb8d-d3be-e0e0-4656-9107f9de0ea9","last_modified":1480349208823},{"guid":"{746505DC-0E21-4667-97F8-72EA6BCF5EEF}","prefs":[],"schema":1480349193877,"blockID":"i842","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128325","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Shopper-Pro","created":"2015-02-06T14:45:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f19c5fb-1c78-cbd6-8a03-1678efb54cbc","last_modified":1480349208766},{"guid":"{51c77233-c0ad-4220-8388-47c11c18b355}","prefs":[],"schema":1480349193877,"blockID":"i580","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1004132","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed into Firefox, in violation of the Add-on Guidelines.","name":"Browser Utility","created":"2014-04-30T13:55:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.1.9999999","minVersion":"0","targetApplication":[]}],"id":"daa2c60a-5009-2c65-a432-161d50bef481","last_modified":1480349208691},{"guid":"{a2bfe612-4cf5-48ea-907c-f3fb25bc9d6b}","prefs":[],"schema":1480349193877,"blockID":"i712","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Xplorer","created":"2014-09-30T15:28:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"13450534-93d7-f2a2-7f0a-e4e3948c4dc1","last_modified":1480349208027},{"guid":"ScorpionSaver@jetpack","prefs":[],"schema":1480349193877,"blockID":"i539","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963826","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enable it in the Add-ons Manager.","why":"This add-on is being silently installed, in violation of the Add-on Guidelines","name":"ScorpionSaver","created":"2014-01-28T14:00:30Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3499c968-6e8b-37f1-5f6e-2384807c2a6d","last_modified":1480349207972},{"guid":"unblocker20@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1212","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 2.0","created":"2016-05-05T18:13:29Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"2.0.0","minVersion":"0","targetApplication":[]}],"id":"57785030-909f-e985-2a82-8bd057781227","last_modified":1480349207912},{"guid":"{D19CA586-DD6C-4a0a-96F8-14644F340D60}","prefs":[],"schema":1480349193877,"blockID":"i42","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=690184","who":"Users of McAfee ScriptScan versions 14.4.0 and below for all versions of Firefox and SeaMonkey.","why":"This add-on causes a high volume of crashes.","name":"McAfee ScriptScan","created":"2011-10-03T09:38:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"14.4.0","minVersion":"0.1","targetApplication":[]}],"id":"1d35ac9d-49df-23cf-51f5-f3c228ad0dc9","last_modified":1480349207877},{"guid":"gjhrjenrengoe@jfdnkwelfwkm.com","prefs":[],"schema":1480349193877,"blockID":"i1042","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1212174","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Avant Player (malware)","created":"2015-10-07T13:12:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d6453893-becc-7617-2050-0db284e0e0db","last_modified":1480349207840},{"guid":"/^(@9338379C-DD5C-4A45-9A36-9733DC806FAE|9338379C-DD5C-4A45-9A36-9733DC806FAE|@EBC7B466-8A28-4061-81B5-10ACC05FFE53|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4222|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4|@b2d6a97c0-4b18-40ed-bce7-3b7d3309e3c4222)$/","prefs":[],"schema":1480349193877,"blockID":"i1079","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1240597","who":"All Firefox users who have these add-ons installed.","why":"These add-ons are malicious, manipulating registry and search settings for users.","name":"Default SearchProtected (malware)","created":"2016-01-18T12:32:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ddc5237e-42e4-1bf1-54d3-a5e5799dd828","last_modified":1480349207815},{"guid":"{33e0daa6-3af3-d8b5-6752-10e949c61516}","prefs":[],"schema":1480349193877,"blockID":"i282","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835683","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on violates our add-on guidelines, bypassing the third party opt-in screen.","name":"Complitly","created":"2013-02-15T12:19:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.1.999","minVersion":"0","targetApplication":[]}],"id":"1f94bc8d-9d5f-c8f5-45c0-ad1f6e147c71","last_modified":1480349207789},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i608","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:20:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.20.*","minVersion":"3.15.18","targetApplication":[]}],"id":"e7d50ff2-5948-d571-6711-37908ccb863f","last_modified":1480349207761},{"guid":"chiang@programmer.net","prefs":[],"schema":1480349193877,"blockID":"i340","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=867156","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that logs keyboard input and sends it to a remote server.","name":"Cache Manager (malware)","created":"2013-04-30T07:44:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d50d0434-78e4-faa7-ce2a-9b0a8bb5120e","last_modified":1480349207736},{"guid":"{63eb5ed4-e1b3-47ec-a253-f8462f205350}","prefs":[],"schema":1480349193877,"blockID":"i786","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"FF-Plugin","created":"2014-11-18T12:33:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ca4558a2-8ce4-3ca0-3d29-63019f680c8c","last_modified":1480349207705},{"guid":"jid1-4vUehhSALFNqCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i634","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033002","who":"All Firefox users who have this version of the add-on installed.","why":"Version 99.7 of the YouTube Plus Plus extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Plus Plus 99.7","created":"2014-07-04T14:13:57Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"99.7","minVersion":"99.7","targetApplication":[]}],"id":"a6d017cb-e33f-2239-4e42-ab4e7cfb19fe","last_modified":1480349207680},{"guid":"{aab02ab1-33cf-4dfa-8a9f-f4e60e976d27}","prefs":[],"schema":1480349193877,"blockID":"i820","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent, in violation of the Add-on Guidelines.","name":"Incredible Web","created":"2015-01-13T09:27:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"847ecc6e-1bc1-f7ff-e1d5-a76e6b8447d2","last_modified":1480349207654},{"guid":"torntv@torntv.com","prefs":[],"schema":1480349193877,"blockID":"i320","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845610","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"TornTV","created":"2013-03-20T16:35:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cdd492b8-8101-74a9-5760-52ff709fd445","last_modified":1480349207608},{"guid":"crossriderapp12555@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i674","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=877836","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"The add-on is silently installed, in violation of our Add-on Guidelines.","name":"JollyWallet","created":"2014-07-22T16:26:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d4467e20-0f71-f0e0-8cd6-40c82b6c7379","last_modified":1480349207561},{"guid":"pluggets@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i435","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=903544","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks users' Facebook accounts and posts spam on their behalf. ","name":"Facebook Pluggets Plugin (malware)","created":"2013-08-09T13:12:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a63fd92-9290-02fb-a2e8-bc1b4424201a","last_modified":1480349207535},{"guid":"344141-fasf9jas08hasoiesj9ia8ws@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1038","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211169","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video Plugin (malware)","created":"2015-10-05T16:42:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7986b7b-9b5a-d372-8147-8b4bd6f5a29b","last_modified":1480349207485},{"guid":"meOYKQEbBBjH5Ml91z0p9Aosgus8P55bjTa4KPfl@jetpack","prefs":[],"schema":1480349193877,"blockID":"i998","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201164","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Smooth Player (malware)","created":"2015-09-07T13:54:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"30c3e511-9e8d-15ee-0867-d61047e56515","last_modified":1480349207370},{"guid":"{8dc5c42e-9204-2a64-8b97-fa94ff8a241f}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i770","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088726","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astrmenda Search","created":"2014-10-30T14:52:52Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8a9c7702-0349-70d6-e64e-3a666ab084c6","last_modified":1480349207320},{"guid":"savingsslider@mybrowserbar.com","prefs":[],"schema":1480349193877,"blockID":"i752","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963788","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Slick Savings","created":"2014-10-17T16:18:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b1faf30-5725-7847-d993-b5cdaabc9829","last_modified":1480349207290},{"guid":"youtubeunblocker__web@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1129","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that is being exploited through this website (unblocker.yt) to change security settings in Firefox and install malicious add-ons.","name":"YouTube Unblocker","created":"2016-03-01T21:20:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aa246b36-0a80-81e3-2129-4847e872d5fe","last_modified":1480349207262},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i612","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:23:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.24.*","minVersion":"3.15.24","targetApplication":[]}],"id":"e0ff9df4-60e4-dbd0-8018-57f395e6610a","last_modified":1480349206818},{"guid":"{1e4ea5fc-09e5-4f45-a43b-c048304899fc}","prefs":[],"schema":1480349193877,"blockID":"i812","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Great Finder","created":"2015-01-06T13:22:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ea40b9f-2423-a2fd-a5e9-4ec1df2715f4","last_modified":1480349206784},{"guid":"psid-vhvxQHMZBOzUZA@jetpack","prefs":[],"schema":1480349193877,"blockID":"i70","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=730059","who":"All Firefox users who have installed this add-on.","why":"Add-on spams Facebook accounts and blocks Facebook warnings.","name":"PublishSync (malware)","created":"2012-02-23T13:44:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f1528b02-7cef-0e80-f747-8bbf1f0f2f06","last_modified":1480349206758},{"guid":"{B18B1E5C-4D81-11E1-9C00-AFEB4824019B}","prefs":[],"schema":1480349193877,"blockID":"i447","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=788838","who":"All Firefox users who have this add-on installed. The add-on can be enabled again in the Add-ons Manager.","why":"This add-on is installed silently, in violation of our Add-on Guidelines.","name":"My Smart Tabs","created":"2013-09-06T16:00:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"40332fae-0444-a141-ade9-8d9e50370f56","last_modified":1480349206733},{"guid":"crossriderapp8812@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i314","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835665","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"Coupon Companion","created":"2013-03-06T14:14:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"06c07e28-0a34-e5ee-e724-491a2f6ce586","last_modified":1480349206708},{"guid":"/^(ffxtlbr@mixidj\\.com|{c0c2693d-2ee8-47b4-9df7-b67a0ee31988}|{67097627-fd8e-4f6b-af4b-ecb65e50112e}|{f6f0f973-a4a3-48cf-9a7a-b7a69c30d71a}|{a3d0e35f-f1da-4ccb-ae77-e9d27777e68d}|{1122b43d-30ee-403f-9bfa-3cc99b0caddd})$/","prefs":[],"schema":1480349193877,"blockID":"i540","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed.","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:07:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4c03ddda-bb3f-f097-0a7b-b7b77b050584","last_modified":1480349206678},{"guid":"hansin@topvest.id","prefs":[],"schema":1480349193877,"blockID":"i836","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1130406","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Inside News (malware)","created":"2015-02-06T14:17:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0945a657-f28d-a02c-01b2-5115b3f90d7a","last_modified":1480349206628},{"guid":"lfind@nijadsoft.net","prefs":[],"schema":1480349193877,"blockID":"i358","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=874131","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Lyrics Finder","created":"2013-05-24T14:09:47Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2307f11c-6216-0dbf-a464-b2921055ce2b","last_modified":1480349206603},{"guid":"plugin@getwebcake.com","prefs":[],"schema":1480349193877,"blockID":"i484","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=938264","who":"All Firefox users who have this add-on installed.","why":"This add-on violates the Add-on Guidelines and is broadly considered to be malware. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"WebCake","created":"2013-11-14T09:55:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2865addd-da1c-20c4-742f-6a2270da2e78","last_modified":1480349206578},{"guid":"{c0c2693d-2ee8-47b4-9df7-b67a0ee31988}","prefs":[],"schema":1480349193877,"blockID":"i354","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=837838","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines.\r\n\r\nUsers who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Mixi DJ","created":"2013-05-23T14:31:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"03a745c3-0ee7-e262-ba31-62d4f78ddb62","last_modified":1480349206525},{"guid":"/^({7316e43a-3ebd-4bb4-95c1-9caf6756c97f}|{0cc09160-108c-4759-bab1-5c12c216e005}|{ef03e721-f564-4333-a331-d4062cee6f2b}|{465fcfbb-47a4-4866-a5d5-d12f9a77da00}|{7557724b-30a9-42a4-98eb-77fcb0fd1be3}|{b7c7d4b0-7a84-4b73-a7ef-48ef59a52c3b})$/","prefs":[],"schema":1480349193877,"blockID":"i520","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947485","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed and using multiple add-on IDs.","name":"appbario7","created":"2013-12-20T13:11:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3901c48-9c06-fecb-87d3-efffd9940c22","last_modified":1480349206491},{"guid":"{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}","prefs":[],"schema":1480349193877,"blockID":"i538","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=964081","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Show Mask ON (malware)","created":"2014-01-27T10:13:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aad90253-8921-b5df-3658-45a70d75f3d7","last_modified":1480349206465},{"guid":"{8E9E3331-D360-4f87-8803-52DE43566502}","prefs":[],"schema":1480349193877,"blockID":"i461","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=906071","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This is a companion add-on for the SweetPacks Toolbar which is blocked due to guideline violations.","name":"Updater By SweetPacks","created":"2013-10-17T16:10:51Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ae8cca6e-4258-545f-9a69-3d908264a701","last_modified":1480349206437},{"guid":"info@bflix.info","prefs":[],"schema":1480349193877,"blockID":"i172","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806802","who":"All Firefox users who have this add-on installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Bflix (malware)","created":"2012-10-30T13:39:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7a9062f4-218d-51d2-9b8c-b282e6eada4f","last_modified":1480349206384},{"guid":"{dff137ae-1ffd-11e3-8277-b8ac6f996f26}","prefs":[],"schema":1480349193877,"blockID":"i450","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=917861","who":"All Firefox users who have this add-on installed.","why":"This is add-on is malware that silently redirects popular search queries to a third party.","name":"Addons Engine (malware)","created":"2013-09-18T16:19:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8e583fe4-1c09-9bea-2473-faecf3260685","last_modified":1480349206312},{"guid":"12x3q@3244516.com","prefs":[],"schema":1480349193877,"blockID":"i493","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=939254","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware and is installed silently in violation of the Add-on Guidelines.","name":"BetterSurf (malware)","created":"2013-12-02T12:49:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"af2a9e74-3753-9ff1-d899-5d1e79ed3dce","last_modified":1480349206286},{"guid":"{20AD702C-661E-4534-8CE9-BA4EC9AD6ECC}","prefs":[],"schema":1480349193877,"blockID":"i626","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1027886","who":"All Firefox users who have this add-on installed.","why":"This add-on is probably silently installed, and is causing significant stability issues for users, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-06-19T15:16:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b9ccabe-8f9a-e3d1-a689-1aefba1f33b6","last_modified":1480349206261},{"guid":"{c5e48979-bd7f-4cf7-9b73-2482a67a4f37}","prefs":[],"schema":1480349193877,"blockID":"i736","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080842","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"ClearThink","created":"2014-10-17T15:22:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6e8b3e4f-2f59-cde3-e6d2-5bc6e216c506","last_modified":1480349206231},{"guid":"{41339ee8-61ed-489d-b049-01e41fd5d7e0}","prefs":[],"schema":1480349193877,"blockID":"i810","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"FireWeb","created":"2014-12-23T10:32:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a35f2ca6-aec4-c01d-170e-650258ebcd2c","last_modified":1480349206165},{"guid":"jid0-l9BxpNUhx1UUgRfKigWzSfrZqAc@jetpack","prefs":[],"schema":1480349193877,"blockID":"i640","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036640","who":"All Firefox users who have this add-on installed.","why":"This add-on attempts to gather private user data and send it to a remote location. It doesn't appear to be very effective at it, but its malicious nature is undeniable.","name":"Bitcoin Mining Software","created":"2014-07-09T14:35:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8fe3c35e-1a6f-a89a-fa96-81bda3b71db1","last_modified":1480349206133},{"guid":"{845cab51-d8d2-472f-8bd9-2b44642d97c2}","prefs":[],"schema":1480349193877,"blockID":"i460","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=927456","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and handles users' settings, violating some of the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Vafmusic9","created":"2013-10-17T15:50:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8538ccb4-3b71-9858-3f6d-c0fff7af58b0","last_modified":1480349205746},{"guid":"SpecialSavings@SpecialSavings.com","prefs":[],"schema":1480349193877,"blockID":"i676","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881511","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This is add-on is generally considered to be unwanted and is probably silently installed, in violation of the Add-on Guidelines.","name":"SpecialSavings","created":"2014-07-22T16:31:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5e921810-fc3a-0729-6749-47e38ad10a22","last_modified":1480349205688},{"guid":"afurladvisor@anchorfree.com","prefs":[],"schema":1480349193877,"blockID":"i434","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844945","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield Helper","created":"2013-08-09T11:26:11Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"083585eb-d7e7-e228-5fbf-bf35c52044e4","last_modified":1480349205645},{"guid":"addonhack@mozilla.kewis.ch","prefs":[],"schema":1480349193877,"blockID":"i994","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1200848","who":"All users who have this add-on installed.","why":"This add-on is a proof of concept of malicious behavior in an add-on. In itself it doesn't cause any harm, but it still needs to be blocked for security reasons.","name":"Addon Hack","created":"2015-09-01T15:32:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"81f75571-ca2a-0e50-a925-daf2037ce63c","last_modified":1480349205584},{"guid":"info@thebflix.com","prefs":[],"schema":1480349193877,"blockID":"i174","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806802","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Bflix (malware)","created":"2012-10-30T13:40:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"811a61d4-9435-133e-6262-fb72486c36b0","last_modified":1480349205526},{"guid":"{EEE6C361-6118-11DC-9C72-001320C79847}","prefs":[],"schema":1480349193877,"blockID":"i392","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881447","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. This violates our Add-on Guidelines.","name":"SweetPacks Toolbar","created":"2013-06-25T12:38:45Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c1dc6607-4c0a-4031-9f14-70ef1ae1edcb","last_modified":1480349205455},{"guid":"/^(4cb61367-efbf-4aa1-8e3a-7f776c9d5763@cdece6e9-b2ef-40a9-b178-291da9870c59\\.com|0efc9c38-1ec7-49ed-8915-53a48b6b7600@e7f17679-2a42-4659-83c5-7ba961fdf75a\\.com|6be3335b-ef79-4b0b-a0ba-b87afbc6f4ad@6bbb4d2e-e33e-4fa5-9b37-934f4fb50182\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i531","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949672","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"Feven","created":"2013-12-20T15:01:22Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"46aa79a9-d329-f713-d4f2-07d31fe7071e","last_modified":1480349205287},{"guid":"afext@anchorfree.com","prefs":[],"schema":1480349193877,"blockID":"i466","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=933988","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't respect user choice, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield Extension","created":"2013-11-07T13:32:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8176f879-bd73-5468-e908-2d7cfc115ac2","last_modified":1480349205108},{"guid":"{FCE04E1F-9378-4f39-96F6-5689A9159E45}","prefs":[],"schema":1480349193877,"blockID":"i920","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:26:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"eb191ff0-20f4-6e04-4344-d880af4faf51","last_modified":1480349204978},{"guid":"{9CE11043-9A15-4207-A565-0C94C42D590D}","prefs":[],"schema":1480349193877,"blockID":"i503","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947384","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that uses a deceptive name to stay in users' systems.","name":"XUL Cache (malware)","created":"2013-12-06T11:58:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dcdae267-8d3a-5671-dff2-f960febbbb20","last_modified":1480349204951},{"guid":"/^[a-z0-9]+@foxysecure[a-z0-9]*\\.com$/","prefs":[],"schema":1480349193877,"blockID":"i766","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088615","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Fox Sec 7","created":"2014-10-30T14:22:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"503fbd7c-04cd-65f3-9d0e-3ecf427b4a8f","last_modified":1480349204925},{"guid":"/^(jid1-W4CLFIRExukJIFW@jetpack|jid1-W4CLFIRExukJIFW@jetpack_1|jid1-W3CLwrP[a-z]+@jetpack)$/","prefs":[],"schema":1480349193877,"blockID":"i1078","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1240561","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that tries to pass itself for the Adobe Flash Player and hides itself in the Add-ons Manager.","name":"Adobe Flash Player (malware)","created":"2016-01-18T10:31:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b026fe67-ec77-a240-2fa1-e78f581a6fe4","last_modified":1480349204899},{"guid":"{0153E448-190B-4987-BDE1-F256CADA672F}","prefs":[],"schema":1480349193877,"blockID":"i914","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:56:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"2bfe0d89-e458-9d0e-f944-ddeaf8c4db6c","last_modified":1480349204871},{"guid":"{77beece6-3997-403a-92fa-0055bfcf88e5}","prefs":[],"schema":1480349193877,"blockID":"i452","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=916966","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, manipulating settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Entrusted11","created":"2013-09-18T16:34:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d348f91f-caeb-a803-dfd9-fd5d285aa0fa","last_modified":1480349204844},{"guid":"dealcabby@jetpack","prefs":[],"schema":1480349193877,"blockID":"i222","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=811435","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed with other software, injecting advertisements in Firefox.","name":"DealCabby","created":"2012-11-29T16:20:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6585f0bd-4f66-71e8-c565-d9762c5c084a","last_modified":1480349204818},{"guid":"{3c9a72a0-b849-40f3-8c84-219109c27554}","prefs":[],"schema":1480349193877,"blockID":"i510","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=951301","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-17T14:27:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7cfa3d0b-0ab2-5e3a-8143-1031c180e32f","last_modified":1480349204778},{"guid":"{4ED1F68A-5463-4931-9384-8FFF5ED91D92}","prefs":[],"schema":1480349193877,"blockID":"i1245","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1286368","who":"All users who have McAfee SiteAdvisor lower than 4.0. \r\n\r\nTo resolve this issue, users will need to uninstall McAfee SiteAdvisor/WebAdvisor, reboot the computer, and then reinstall McAfee SiteAdvisor/WebAdvisor. \r\n\r\nFor detailed instructions, please refer to the McAfee support knowledge base.","why":"Old versions of McAfee SiteAdvisor cause startup crashes starting with Firefox 48.0 beta.","name":"McAfee SiteAdvisor lower than 4.0","created":"2016-07-14T21:24:02Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.9.9","minVersion":"0","targetApplication":[]}],"id":"d727d8c5-3329-c98a-7c7e-38b0813ca516","last_modified":1480349204748},{"guid":"{2aab351c-ad56-444c-b935-38bffe18ad26}","prefs":[],"schema":1480349193877,"blockID":"i500","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946087","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Adobe Photo (malware)","created":"2013-12-04T15:29:44Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f7a76d34-ddcd-155e-9fae-5967bd796041","last_modified":1480349204716},{"guid":"jid1-4P0kohSJxU1qGg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i488","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=942935","who":"All Firefox users who have version 1.2.50 of the Hola extension. Updating to the latest version should remove the block.","why":"Version 1.2.50 of the Hola extension is causing frequent crashes in Firefox. All users are strongly recommended to update to the latest version, which shouldn't have this problem.","name":"Hola, version 1.2.50","created":"2013-11-25T12:14:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.50","minVersion":"1.2.50","targetApplication":[]}],"id":"5c7f1635-b39d-4278-5f95-9042399c776e","last_modified":1480349204668},{"guid":"{0A92F062-6AC6-8180-5881-B6E0C0DC2CC5}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i864","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131220","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and makes unwanted settings changes, in violation of our Add-on Guidelines.","name":"BlockAndSurf","created":"2015-02-26T12:56:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"acb16d1c-6274-93a3-7c1c-7ed36ede64a9","last_modified":1480349204612},{"guid":"jid0-Y6TVIzs0r7r4xkOogmJPNAGFGBw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i322","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=847018","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:39:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"54df22cd-19ce-a7f0-63cc-ffe3113748b9","last_modified":1480349204532},{"guid":"trackerbird@bustany.org","prefs":[],"schema":1480349193877,"blockID":"i986","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1189264","who":"All Thunderbird users who have this version of the add-on installed on Thunderbird 38.0a2 and above.","why":"This add-on is causing consistent crashes on Thunderbird 38.0a2 and above.","name":"trackerbird 1.2.6","created":"2015-08-17T15:56:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.6","minVersion":"1.2.6","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"}]}],"id":"bb1c699e-8790-4528-0b6d-4f83b7a3152d","last_modified":1480349204041},{"guid":"{0134af61-7a0c-4649-aeca-90d776060cb3}","prefs":[],"schema":1480349193877,"blockID":"i448","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=912746","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"KeyBar add-on","created":"2013-09-13T16:15:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cf428416-4974-8bb4-7928-c0cb2cfe7957","last_modified":1480349203968},{"guid":"/^(firefox@vebergreat\\.net|EFGLQA@78ETGYN-0W7FN789T87\\.COM)$/","prefs":[],"schema":1480349193877,"blockID":"i564","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974104","who":"All Firefox users who have these add-ons installed. If you wish to continue using these add-ons, you can enable them in the Add-ons Manager.","why":"These add-ons are silently installed by the Free Driver Scout installer, in violation of our Add-on Guidelines.","name":"veberGreat and vis (Free Driver Scout bundle)","created":"2014-03-05T13:02:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"487538f1-698e-147e-6395-986759ceed7e","last_modified":1480349203902},{"guid":"69ffxtbr@PackageTracer_69.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i882","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1153001","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be malware, hijacking user's settings, in violation of the Add-on Guidelines.","name":"PackageTracer","created":"2015-04-10T16:18:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0d37b4e0-3c60-fdad-dd8c-59baff6eae87","last_modified":1480349203836},{"guid":"{ACAA314B-EEBA-48e4-AD47-84E31C44796C}","prefs":[],"schema":1480349193877,"blockID":"i496","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945530","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making settings changes that can't be easily reverted.","name":"DVDVideoSoft Menu","created":"2013-12-03T16:07:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"70d2c912-8d04-8065-56d6-d793b13d5f67","last_modified":1480349203779},{"guid":"jid1-4vUehhSALFNqCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i632","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033002","who":"All Firefox users who have this version of the add-on installed.","why":"Version 100.7 of the YouTube Plus Plus extension isn't developed by the original developer, and is likely malicious in nature. It violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Plus Plus 100.7","created":"2014-07-01T13:16:55Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"100.7","minVersion":"100.7","targetApplication":[]}],"id":"8bef6026-6697-99cd-7c1f-812877c4211d","last_modified":1480349203658},{"guid":"{a9bb9fa0-4122-4c75-bd9a-bc27db3f9155}","prefs":[],"schema":1480349193877,"blockID":"i404","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb7a1dc7-16a0-4f70-8289-4df494e0d0fa","last_modified":1480349203633},{"guid":"P2@D.edu","prefs":[],"schema":1480349193877,"blockID":"i850","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128269","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"unIsaless","created":"2015-02-09T15:29:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"49536a29-fc7e-9fd0-f415-e15ac090fa56","last_modified":1480349203605},{"guid":"linksicle@linksicle.com","prefs":[],"schema":1480349193877,"blockID":"i472","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9b5b15b3-6da7-cb7c-3c44-30b4fe079d52","last_modified":1480349203581},{"guid":"{377e5d4d-77e5-476a-8716-7e70a9272da0}","prefs":[],"schema":1480349193877,"blockID":"i398","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:15:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ea94df32-2a85-23da-43f7-3fc5714530ec","last_modified":1480349203519},{"guid":"{4933189D-C7F7-4C6E-834B-A29F087BFD23}","prefs":[],"schema":1480349193877,"blockID":"i437","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=900695","who":"All Firefox users.","why":"This add-on is widely reported to be malware.","name":"Win32.SMSWebalta (malware)","created":"2013-08-09T15:14:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cbef1357-d6bc-c8d3-7a82-44af6b1c390f","last_modified":1480349203486},{"guid":"{ADFA33FD-16F5-4355-8504-DF4D664CFE10}","prefs":[],"schema":1480349193877,"blockID":"i306","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844972","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed, bypassing our third-party opt-in screen, in violation of our Add-on Guidelines. It's also possible that it changes user settings without their consent.","name":"Nation Toolbar","created":"2013-02-28T12:56:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"017fd151-37ca-4646-4763-1d303fb918fa","last_modified":1480349203460},{"guid":"detgdp@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i884","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152614","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware, hijacking user settings, in violation of the Add-on Guidelines.","name":"Security Protection (malware)","created":"2015-04-10T16:21:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1b5cc88e-499d-2a47-d793-982d4c05e6ee","last_modified":1480349203433},{"guid":"/^(67314b39-24e6-4f05-99f3-3f88c7cddd17@6c5fa560-13a3-4d42-8e90-53d9930111f9\\.com|ffxtlbr@visualbee\\.com|{7aeae561-714b-45f6-ace3-4a8aed6e227b}|{7093ee04-f2e4-4637-a667-0f730797b3a0}|{53c4024f-5a2e-4f2a-b33e-e8784d730938})$/","prefs":[],"schema":1480349193877,"blockID":"i514","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947473","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by using multiple add-on IDs and making unwanted settings changes.","name":"VisualBee Toolbar","created":"2013-12-20T12:25:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f91eee1-7303-3f97-dfe6-1e897a156c7f","last_modified":1480349203408},{"guid":"FXqG@xeeR.net","prefs":["browser.startup.homepage"],"schema":1480349193877,"blockID":"i720","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems and changes settings without consent, in violation of the Add-on Guidelines.","name":"GoSSave","created":"2014-10-02T12:23:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8ebbc061-a4ff-b75b-ec42-eb17c42a2956","last_modified":1480349203341},{"guid":"{87934c42-161d-45bc-8cef-ef18abe2a30c}","prefs":[],"schema":1480349193877,"blockID":"i547","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=798621","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is silently installed and makes various unwanted changes, in violation of the Add-on Guidelines.","name":"Ad-Aware Security Toolbar","created":"2014-01-30T12:42:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.7.9999999999","minVersion":"0","targetApplication":[]}],"id":"bcfbc502-24c2-4699-7435-e4837118f05a","last_modified":1480349203310},{"guid":"kallow@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i495","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945426","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Facebook Security Service (malware)","created":"2013-12-02T15:09:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1a2c37a9-e7cc-2d03-2043-098d36b8aca2","last_modified":1480349203247},{"guid":"support@lastpass.com","prefs":[],"schema":1480349193877,"blockID":"i1261","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1289907","who":"All users who install affected versions of this add-on - beta versions 4.0 to 4.1.20a from addons.mozilla.org or lastpass.com.","why":"LastPass have announced there are security issues that would allow a malicious website to perform some actions (e.g. deleting passwords) without the user's knowledge. Beta versions 4.0 to 4.1.20a of their add-on that were available from addons.mozilla.org are affected and Lastpass also distributed these versions direct from their website.","name":"LastPass addon","created":"2016-07-29T14:17:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.1.20a","minVersion":"4.0.0a","targetApplication":[]}],"id":"ffe94023-b4aa-87ac-962c-5beabe34b1a0","last_modified":1480349203208},{"guid":"008abed2-b43a-46c9-9a5b-a771c87b82da@1ad61d53-2bdc-4484-a26b-b888ecae1906.com","prefs":[],"schema":1480349193877,"blockID":"i528","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949565","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed.","name":"weDownload Manager Pro","created":"2013-12-20T14:40:58Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"da46065f-1c68-78f7-80fc-8ae07b5df68d","last_modified":1480349203131},{"guid":"{25dd52dc-89a8-469d-9e8f-8d483095d1e8}","prefs":[],"schema":1480349193877,"blockID":"i714","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Web Counselor","created":"2014-10-01T15:36:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e46c31ad-0ab3-e48a-47aa-9fa91b675fda","last_modified":1480349203066},{"guid":"{B1FC07E1-E05B-4567-8891-E63FBE545BA8}","prefs":[],"schema":1480349193877,"blockID":"i926","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:28:46Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"09868783-261a-ac24-059d-fc772218c1ba","last_modified":1480349202708},{"guid":"/^(torntv@torntv\\.com|trtv3@trtv\\.com|torntv2@torntv\\.com|e2fd07a6-e282-4f2e-8965-85565fcb6384@b69158e6-3c3b-476c-9d98-ae5838c5b707\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i529","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949559","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by being silently installed.","name":"TornTV","created":"2013-12-20T14:46:03Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"040e5ec2-ea34-816a-f99f-93296ce845e8","last_modified":1480349202677},{"guid":"249911bc-d1bd-4d66-8c17-df533609e6d8@c76f3de9-939e-4922-b73c-5d7a3139375d.com","prefs":[],"schema":1480349193877,"blockID":"i532","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949672","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and using multiple IDs.","name":"Feven","created":"2013-12-20T15:02:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d32b850d-82d5-b63d-087c-fb2041b2c232","last_modified":1480349202631},{"guid":"thefoxonlybetter@quicksaver","prefs":[],"schema":1480349193877,"blockID":"i704","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1053469","who":"All Firefox users who have any of these versions of the add-on installed.","why":"Certain versions of The Fox, Only Better weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"The Fox, Only Better (malicious versions)","created":"2014-08-27T14:49:02Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"0.*","minVersion":"0","targetApplication":[]}],"id":"79ea6621-b414-17a4-4872-bfc4af7fd428","last_modified":1480349202588},{"guid":"{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}","prefs":[],"schema":1480349193877,"blockID":"i429","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=899178","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that spreads spam through Facebook.","name":"Video Player 1.3 (malware)","created":"2013-07-30T14:31:17Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d98b2b76-4082-3387-ae33-971d973fa278","last_modified":1480349202541},{"guid":"firefoxaddon@youtubeenhancer.com","prefs":[],"schema":1480349193877,"blockID":"i648","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouTube Enhancer Plus extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube Enhancer Plus, versions between 199.7.0 and 208.7.0","created":"2014-07-10T15:12:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.7.0","minVersion":"199.7.0","targetApplication":[]}],"id":"7e64d7fc-ff16-8687-dbd1-bc4c7dfc5097","last_modified":1480349202462},{"guid":"addon@defaulttab.com","prefs":[],"schema":1480349193877,"blockID":"i362","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=863387","who":"All users who have this add-on installed. Users who wish to enable it again can do so in the Add-ons Manager tab.","why":"Old versions of this add-on had been silently installed into users' systems, without showing the opt-in install page that is built into Firefox.","name":"Default Tab","created":"2013-06-06T12:57:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.4.4","minVersion":"0","targetApplication":[]}],"id":"df3fe753-5bae-bfb4-022b-6b6bfc534937","last_modified":1480349202429},{"guid":"{7D4F1959-3F72-49d5-8E59-F02F8AA6815D}","prefs":[],"schema":1480349193877,"blockID":"i394","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=881447","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This is a companion add-on for the SweetPacks Toolbar which is blocked due to guideline violations.","name":"Updater By SweetPacks","created":"2013-06-25T12:40:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"851c2b8e-ea19-3a63-eac5-f931a8da5d6e","last_modified":1480349202341},{"guid":"g@uzcERQ6ko.net","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i776","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines","name":"GoSave","created":"2014-10-31T16:23:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ee1e1a44-b51b-9f12-819d-64c3e515a147","last_modified":1480349202307},{"guid":"ffxtlbr@incredibar.com","prefs":[],"schema":1480349193877,"blockID":"i318","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812264","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"IncrediBar","created":"2013-03-20T14:40:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9e84b07c-84d5-c932-85f2-589713d7e380","last_modified":1480349202280},{"guid":"M1uwW0@47z8gRpK8sULXXLivB.com","prefs":[],"schema":1480349193877,"blockID":"i870","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1131159","who":"All users who have this add-on installed.","why":"This is a malicious add-on that goes by the the name \"Flash Player 11\".","name":"Flash Player 11 (malware)","created":"2015-03-04T14:34:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"71d961b2-37d1-d393-76f5-3afeef57e749","last_modified":1480349202252},{"guid":"jid1-qj0w91o64N7Eeg@jetpack","prefs":[],"schema":1480349193877,"blockID":"i650","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouTube ALL HTML5 extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouTube ALL HTML5, versions between 39.5.1 and 47.0.4","created":"2014-07-10T15:14:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"47.0.4","minVersion":"39.5.1","targetApplication":[]}],"id":"b30b1f7a-2a30-a6cd-fc20-6c9cb23c7198","last_modified":1480349202186},{"guid":"4zffxtbr-bs@VideoDownloadConverter_4z.com","prefs":[],"schema":1480349193877,"blockID":"i507","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949266","who":"All Firefox users who have this add-on installed.","why":"Certain versions of this add-on contains an executable that is flagged by multiple tools as malware. Newer versions no longer use it.","name":"VideoDownloadConverter","created":"2013-12-12T15:37:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.75.3.25126","minVersion":"0","targetApplication":[]}],"id":"0a0f106a-ecc6-c537-1818-b36934943e91","last_modified":1480349202156},{"guid":"hdv@vovcacik.addons.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i656","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the High Definition Video extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"High Definition Video, version 102.0","created":"2014-07-10T15:22:59Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"102.0","minVersion":"102.0","targetApplication":[]}],"id":"972249b2-bba8-b508-2ead-c336631135ac","last_modified":1480349202125},{"guid":"@video_downloader_pro","prefs":[],"schema":1480349193877,"blockID":"i1265","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1298335","who":"Users of versions of 1.2.1 to 1.2.5 inclusive.","why":"Versions 1.2.1 to 1.2.5 of Video Downloader Pro included code that violated our polices - affected versions send every visited url to a remote server without the user's consent. Versions older than 1.2.1 and more recent than 1.2.5 are okay.","name":"Video Downloader Pro","created":"2016-08-26T18:26:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.2.5","minVersion":"1.2.1","targetApplication":[]}],"id":"ff9c8def-7d50-66b4-d42a-f9a4b04bd224","last_modified":1480349202099},{"guid":"contato@facefollow.net","prefs":[],"schema":1480349193877,"blockID":"i509","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950846","who":"All Firefox users who have this add-on installed.","why":"This add-on spams users' Facebook accounts.","name":"Face follow","created":"2013-12-16T16:15:15Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"56f15747-af8c-342c-6877-a41eeacded84","last_modified":1480349202067},{"guid":"wecarereminder@bryan","prefs":[],"schema":1480349193877,"blockID":"i666","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=818614","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is being silently installed by various software packages, in violation of the Add-on Guidelines.","name":"We-Care Reminder","created":"2014-07-10T16:18:36Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"51e0ead7-144c-c1f4-32f2-25fc5fcde870","last_modified":1480349202039},{"guid":"/^({83a8ce1b-683c-4784-b86d-9eb601b59f38}|{ef1feedd-d8da-4930-96f1-0a1a598375c6}|{79ff1aae-701f-4ca5-aea3-74b3eac6f01b}|{8a184644-a171-4b05-bc9a-28d75ffc9505}|{bc09c55d-0375-4dcc-836e-0e3c8addfbda}|{cef81415-2059-4dd5-9829-1aef3cf27f4f})$/","prefs":[],"schema":1480349193877,"blockID":"i526","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949566","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and uses multiple IDs.","name":"KeyBar add-on","created":"2013-12-20T14:12:31Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9dfa4e92-bbf2-66d1-59a9-51402d1d226c","last_modified":1480349202010},{"guid":"{d9284e50-81fc-11da-a72b-0800200c9a66}","prefs":[],"schema":1480349193877,"blockID":"i806","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1106948","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable the add-on in the Add-on Manager.","why":"Starting with Firefox 34, current versions of the Yoono add-on cause all tabs to appear blank.","name":"Yoono","created":"2014-12-16T08:35:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.7.34","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"34.0a1"}]}],"id":"ccdceb04-3083-012f-9d9f-aac85f10b494","last_modified":1480349201976},{"guid":"{f2548724-373f-45fe-be6a-3a85e87b7711}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i768","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1088726","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astro New Tab","created":"2014-10-30T14:52:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8510e9e2-c7d8-90d0-a2ff-eb09293acc6e","last_modified":1480349201854},{"guid":"KSqOiTeSJEDZtTGuvc18PdPmYodROmYzfpoyiCr2@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1032","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211172","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Video Player (malware)","created":"2015-10-05T16:22:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3d9188ac-235f-773a-52a2-261b3ea9c03c","last_modified":1480349201504},{"guid":"{849ded12-59e9-4dae-8f86-918b70d213dc}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i708","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1047102","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes homepage and search settings without the user's consent, in violation of the Add-on Guidelines.","name":"Astromenda New Tab","created":"2014-09-02T16:29:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a319bfee-464f-1c33-61ad-738c52842fbd","last_modified":1480349201453},{"guid":"grjkntbhr@hgergerherg.com","prefs":[],"schema":1480349193877,"blockID":"i1018","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208196","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"GreenPlayer (malware)","created":"2015-09-24T16:04:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"9c47d940-bdd9-729f-e32e-1774d87f24b5","last_modified":1480349201425},{"guid":"quick_start@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i588","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011316","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware that is installed without user consent.","name":"Quick Start (malware)","created":"2014-06-03T15:53:15Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2affbebe-8776-3edb-28b9-237cb8b85f97","last_modified":1480349201398},{"guid":"/^(matchersite(pro(srcs?)?)?\\@matchersite(pro(srcs?)?)?\\.com)|((pro)?sitematcher(_srcs?|pro|site|sitesrc|-generic)?\\@(pro)?sitematcher(_srcs?|pro|site|sitesrc|-generic)?\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i668","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1039892","who":"All Firefox users who have any of these add-ons installed. User who wish to continue using these add-ons can enable them in the Add-ons Manager.","why":"This is a group of add-ons that are being distributed under multiple different IDs and likely being silently installed, in violation of the Add-on Guidelines.","name":"Site Matcher","created":"2014-07-17T14:35:14Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"52e1a2de-ab35-be27-4810-334f681ccc4a","last_modified":1480349201372},{"guid":"{EEF73632-A085-4fd3-A778-ECD82C8CB297}","prefs":[],"schema":1480349193877,"blockID":"i165","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have these add-ons installed.","why":"These are malicious add-ons that are distributed with a trojan and negatively affect web browsing.","name":"Codec-M (malware)","created":"2012-10-29T16:41:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e5ecd02a-20ee-749b-d5cf-3d74d1173a1f","last_modified":1480349201262},{"guid":"firefox-extension@mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i688","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1049533","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hides itself under the name Java_plugin, among others.","name":"FinFisher (malware)","created":"2014-08-06T17:13:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"98aca74a-69c7-9960-cccc-096a4a4adc6c","last_modified":1480349201235},{"guid":"jid1-vW9nopuIAJiRHw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i570","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=990291","who":"All Firefox users who have this add-on installed. Those who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, reverts settings changes to enforce its own, and is also causing stability problems in Firefox, all in violation of the Add-on Guidelines.","name":"SmileysWeLove","created":"2014-03-31T16:17:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bf2abd66-f910-650e-89aa-cd1d5c2f8a89","last_modified":1480349201204},{"guid":"87aukfkausiopoawjsuifhasefgased278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1050","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1220461","who":"All users who have this add-on installed.","why":"This is a malicious add-on that poses as a video update and hijacks Facebook accounts.","name":"Trace Video (malware)","created":"2015-11-02T14:53:21Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cb4cfac0-79c2-0fbf-206a-324aa3abbea5","last_modified":1480349201157},{"guid":"{e44a1809-4d10-4ab8-b343-3326b64c7cdd}","prefs":[],"schema":1480349193877,"blockID":"i451","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=916966","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, manipulating settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Entrusted","created":"2013-09-18T16:33:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ad5f53ed-7a43-cb1f-cbd7-41808fac1791","last_modified":1480349201128},{"guid":"{21EAF666-26B3-4A3C-ABD0-CA2F5A326744}","prefs":[],"schema":1480349193877,"blockID":"i620","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024752","who":"All Firefox users who have this add-on installed.","why":"This add-on is probably silently installed, and is causing significant stability issues for users, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-06-12T15:27:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2d8833db-01a7-a758-080f-19e47abc54cb","last_modified":1480349201096},{"guid":"{1FD91A9C-410C-4090-BBCC-55D3450EF433}","prefs":[],"schema":1480349193877,"blockID":"i338","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844979","who":"All Firefox users who have this add-on installed.","why":"This extension overrides search settings, and monitors any further changes done to them so that they can be reverted. This violates our add-on guidelines.","name":"DataMngr (malware)","created":"2013-04-24T11:30:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2e35995f-bec6-aa2b-3372-346d3325f72e","last_modified":1480349201059},{"guid":"9598582LLKmjasieijkaslesae@jetpack","prefs":[],"schema":1480349193877,"blockID":"i996","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1201165","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Secure Player (malware)","created":"2015-09-07T13:50:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"52f9c6e7-f7d5-f52e-cc35-eb99ef8b4b6a","last_modified":1480349201029},{"guid":"{bf7380fa-e3b4-4db2-af3e-9d8783a45bfc}","prefs":[],"schema":1480349193877,"blockID":"i406","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=776404","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on changes search settings without user interaction, and fails to reset them after it is removed. This violates our Add-on Guidelines.","name":"uTorrentBar","created":"2013-06-27T10:46:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3bcefc4b-110c-f3b8-17ad-f9fc97c1120a","last_modified":1480349201000},{"guid":"{ce7e73df-6a44-4028-8079-5927a588c948}","prefs":[],"schema":1480349193877,"blockID":"i117","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=781269","who":"All Firefox users who have this add-on installed.","why":"The Search By Image (by Google) extension causes very high CPU utilization during regular browsing, often damaging user experience significantly, in a way that is very difficult to associate with the extension.\r\n\r\nUsers who want to continue using the add-on regardless of its performance impact can enable it in the Add-ons Manager.","name":"Search By Image (by Google)","created":"2012-08-10T08:50:52Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0.8","minVersion":"0","targetApplication":[]}],"id":"fb1f9aed-2f1f-3e2c-705d-3b34ca9168b6","last_modified":1480349200972},{"guid":"{424b0d11-e7fe-4a04-b7df-8f2c77f58aaf}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i800","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda NT","created":"2014-12-15T10:51:56Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"07bdf6aa-cfc8-ed21-6b36-6f90af02b169","last_modified":1480349200939},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i618","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.\r\n","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.\r\n","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:25:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.31.*","minVersion":"3.15.31","targetApplication":[]}],"id":"825feb43-d6c2-7911-4189-6f589f612c34","last_modified":1480349200911},{"guid":"{167d9323-f7cc-48f5-948a-6f012831a69f}","prefs":[],"schema":1480349193877,"blockID":"i262","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=812303","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and doesn't do much more than changing the users' settings, without reverting them on removal.","name":"WhiteSmoke (malware)","created":"2013-01-29T13:33:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a8f249fe-3db8-64b8-da89-7b584337a7af","last_modified":1480349200885},{"guid":"/^({988919ff-0cd8-4d0c-bc7e-60d55a49eb64}|{494b9726-9084-415c-a499-68c07e187244}|{55b95864-3251-45e9-bb30-1a82589aaff1}|{eef3855c-fc2d-41e6-8d91-d368f51b3055}|{90a1b331-c2b4-4933-9f63-ba7b84d60d58}|{d2cf9842-af95-48cd-b873-bfbb48cd7f5e})$/","prefs":[],"schema":1480349193877,"blockID":"i541","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:09:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"36196aed-9d0d-ebee-adf1-d1f7fadbc48f","last_modified":1480349200819},{"guid":"{29b136c9-938d-4d3d-8df8-d649d9b74d02}","prefs":[],"schema":1480349193877,"blockID":"i598","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011322","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, in violation with our Add-on Guidelines.","name":"Mega Browse","created":"2014-06-12T13:21:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"63b1c965-27c3-cd06-1b76-8721add39edf","last_modified":1480349200775},{"guid":"{6e7f6f9f-8ce6-4611-add2-05f0f7049ee6}","prefs":[],"schema":1480349193877,"blockID":"i868","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1086574","who":"All users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of our Add-on Guidelines.","name":"Word Proser","created":"2015-02-26T14:58:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f54797da-cdcd-351a-c95e-874b64b0d226","last_modified":1480349200690},{"guid":"{02edb56b-9b33-435b-b7df-b2843273a694}","prefs":[],"schema":1480349193877,"blockID":"i438","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=896581","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines. It is installed bypassing the Firefox opt-in screen, and manipulates settings without reverting them on removal. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"KeyBar Toolbar","created":"2013-08-09T15:27:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"896710d2-5a65-e9b0-845b-05aa72c2bd51","last_modified":1480349200338},{"guid":"{e1aaa9f8-4500-47f1-9a0a-b02bd60e4076}","prefs":[],"schema":1480349193877,"blockID":"i646","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Youtube Video Replay extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Youtube Video Replay, version 178.7.0","created":"2014-07-10T15:10:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"178.7.0","minVersion":"178.7.0","targetApplication":[]}],"id":"ac5d1083-6753-bbc1-a83d-c63c35371b22","last_modified":1480349200312},{"guid":"{1cdbda58-45f8-4d91-b566-8edce18f8d0a}","prefs":[],"schema":1480349193877,"blockID":"i724","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080835","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Counselor Pro","created":"2014-10-13T16:00:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"7b70bd36-d2f7-26fa-9038-8b8dd132cd81","last_modified":1480349200288},{"guid":"{b12785f5-d8d0-4530-a3ea-5c4263b85bef}","prefs":[],"schema":1480349193877,"blockID":"i988","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1161573","who":"All users who have this add-on installed. Those who wish continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on overrides user's preferences without consent, in violation of the Add-on Guidelines.","name":"Hero Fighter Community Toolbar","created":"2015-08-17T16:04:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e6d73f2-e8e3-af69-866e-30d3977b09e4","last_modified":1480349200171},{"guid":"{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}","prefs":[],"schema":1480349193877,"blockID":"i39","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=665775","who":"Users of MediaBar versions 4.3.1.00 and below in all versions of Firefox.","why":"This add-on causes a high volume of crashes and is incompatible with certain versions of Firefox.","name":"MediaBar","created":"2011-07-19T10:18:12Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.3.1.00","minVersion":"0.1","targetApplication":[]}],"id":"e928a115-9d8e-86a4-e2c7-de39627bd9bf","last_modified":1480349200047},{"guid":"{9edd0ea8-2819-47c2-8320-b007d5996f8a}","prefs":["browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i684","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1033857","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is believed to be silently installed in Firefox, in violation of the Add-on Guidelines.","name":"webget","created":"2014-08-06T13:33:33Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d38561f5-370f-14be-1443-a74dad29b1f3","last_modified":1480349199962},{"guid":"/^({ad9a41d2-9a49-4fa6-a79e-71a0785364c8})|(ffxtlbr@mysearchdial\\.com)$/","prefs":["browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i670","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036740","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on has been repeatedly been silently installed into users' systems, and is known for changing the default search without user consent, in violation of the Add-on Guidelines.","name":"MySearchDial","created":"2014-07-18T15:47:35Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a04075e6-5df2-2e1f-85a6-3a0171247349","last_modified":1480349199927},{"guid":"odtffplugin@ibm.com","prefs":[],"schema":1480349193877,"blockID":"i982","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1190630","who":"All users who have these versions installed. The latest versions of this add-on aren't blocked, so updating to them should be sufficient to fix this problem.","why":"Certain versions of the IBM Remote Control add-on could leave a machine vulnerable to run untrusted code.","name":"IBM Endpoint Manager for Remote Control 9.0.1.1 to 9.0.1.100","created":"2015-08-11T11:25:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.0.1.100","minVersion":"9.0.1.1","targetApplication":[]}],"id":"f6e3e5d2-9331-1097-ba4b-cf2e484b7187","last_modified":1480349199886},{"guid":"support@todoist.com","prefs":[],"schema":1480349193877,"blockID":"i1030","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1205479","who":"All users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is sending all sites visited by the user to a remote server, additionally doing so in an unsafe way.","name":"Todoist","created":"2015-10-01T16:53:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.9","minVersion":"0","targetApplication":[]}],"id":"d0a84aab-0661-b3c5-c184-a2fd3f9dfb9c","last_modified":1480349199850},{"guid":"/^({1f43c8af-e9e4-4e5a-b77a-f51c7a916324}|{3a3bd700-322e-440a-8a6a-37243d5c7f92}|{6a5b9fc2-733a-4964-a96a-958dd3f3878e}|{7b5d6334-8bc7-4bca-a13e-ff218d5a3f17}|{b87bca5b-2b5d-4ae8-ad53-997aa2e238d4}|{bf8e032b-150f-4656-8f2d-6b5c4a646e0d})$/","prefs":[],"schema":1480349193877,"blockID":"i1136","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hides itself from view and disables various security features in Firefox.","name":"Watcher (malware)","created":"2016-03-04T17:56:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a2d0378f-ebe4-678c-62d8-2e4c6a613c17","last_modified":1480349199818},{"guid":"liiros@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i814","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119657","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent and performs unwanted operations.","name":"One Tab (malware)","created":"2015-01-09T12:49:05Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"387c054d-cc9f-7ebd-c814-b4c1fbcb2880","last_modified":1480349199791},{"guid":"youtubeunblocker@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1128","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that is being exploited through this website (unblocker.yt) to change security settings in Firefox and install malicious add-ons.","name":"YouTube Unblocker","created":"2016-03-01T21:18:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3395fce1-42dd-e31a-1466-2da3f32456a0","last_modified":1480349199768},{"guid":"{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}","prefs":[],"schema":1480349193877,"blockID":"i916","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1170633","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-02T09:57:38Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"94fba774-c4e6-046a-bc7d-ede787a9d0fe","last_modified":1480349199738},{"guid":"{b64982b1-d112-42b5-b1e4-d3867c4533f8}","prefs":[],"schema":1480349193877,"blockID":"i167","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=805973","who":"All Firefox users who have this add-on installed.","why":"This add-on is a frequent cause for browser crashes and other problems.","name":"Browser Manager","created":"2012-10-29T17:17:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"00bbe501-2d27-7a1c-c344-6eea1c707473","last_modified":1480349199673},{"guid":"{58bd07eb-0ee0-4df0-8121-dc9b693373df}","prefs":[],"schema":1480349193877,"blockID":"i286","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=842206","who":"All Firefox users who have this extension installed.","why":"This extension is malicious and is installed under false pretenses, causing problems for many Firefox users. Note that this is not the same BrowserProtect extension that is listed on our add-ons site. That one is safe to use.","name":"Browser Protect / bProtector (malware)","created":"2013-02-18T10:54:28Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b40a60d3-b9eb-09eb-bb02-d50b27aaac9f","last_modified":1480349199619},{"guid":"trtv3@trtv.com","prefs":[],"schema":1480349193877,"blockID":"i465","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=845610","who":"All Firefox users who have this add-on installed.","why":"This add-on doesn't follow our Add-on Guidelines, bypassing our third party install opt-in screen. Users who wish to continue using this extension can enable it in the Add-ons Manager.","name":"TornTV","created":"2013-11-01T15:21:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3d4d8a33-2eff-2556-c699-9be0841a8cd4","last_modified":1480349199560},{"guid":"youtube@downloader.yt","prefs":[],"schema":1480349193877,"blockID":"i1231","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1278932","who":"All users who have this add-on installed.","why":"The add-on has a mechanism that updates certain configuration files from the developer\u2019s website. This mechanism has a vulnerability that can being exploited through this website (downloader.yt) to change security settings in Firefox and/or install malicious add-ons. \r\n","name":"YouTube downloader","created":"2016-06-09T14:50:27Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8514eaee-850c-e27a-a058-8badeeafc26e","last_modified":1480349199528},{"guid":"low_quality_flash@pie2k.com","prefs":[],"schema":1480349193877,"blockID":"i658","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the Low Quality Flash extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"Low Quality Flash, versions between 46.2 and 47.1","created":"2014-07-10T15:27:51Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"47.1","minVersion":"46.2","targetApplication":[]}],"id":"b869fae6-c18c-0d39-59a2-603814656404","last_modified":1480349199504},{"guid":"{d2cf9842-af95-48cd-b873-bfbb48cd7f5e}","prefs":[],"schema":1480349193877,"blockID":"i439","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=902569","who":"All Firefox users who have this add-on installed.","why":"This is another instance of the previously blocked Mixi DJ add-on, which doesn't follow our Add-on Guidelines. If you wish to continue using it, it can be enabled in the Add-ons Manager.","name":"Mixi DJ V45","created":"2013-08-09T16:08:18Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e81c31fc-265e-61b9-d4c1-0e2f31f1652e","last_modified":1480349199478},{"guid":"/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/","prefs":[],"schema":1480349193877,"blockID":"i624","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947482","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is known to change user settings without their consent, is distributed under multiple add-on IDs, and is also correlated with reports of tab functions being broken in Firefox, in violation of the Add-on Guidelines.\r\n","name":"WiseConvert","created":"2014-06-18T13:50:38Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ed57d7a6-5996-c7da-8e07-1ad125183e84","last_modified":1480349199446},{"guid":"{f894a29a-f065-40c3-bb19-da6057778493}","prefs":[],"schema":1480349193877,"blockID":"i742","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080817","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on appears to be silently installed into users' systems, and changes settings without consent, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-10-17T15:46:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"39d8334e-4b7c-4336-2d90-e6aa2d783967","last_modified":1480349199083},{"guid":"plugin@analytic-s.com","prefs":[],"schema":1480349193877,"blockID":"i467","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935797","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Analytics","created":"2013-11-07T14:08:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ffbed3f3-e5c9-bc6c-7530-f68f47b7efd6","last_modified":1480349199026},{"guid":"{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}","prefs":[],"schema":1480349193877,"blockID":"i678","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=895668","who":"All Firefox users who have this add-on installed. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on is generally silently installed, in violation of the Add-on Guidelines.","name":"DataMngr","created":"2014-07-23T14:12:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"151021fc-ce4e-a734-e075-4ece19610f64","last_modified":1480349198947},{"guid":"HxLVJK1ioigz9WEWo8QgCs3evE7uW6LEExAniBGG@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1036","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211170","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Mega Player (malware)","created":"2015-10-05T16:37:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32e34b41-a73c-72d4-c96c-136917ad1d4d","last_modified":1480349198894},{"guid":"{6af08a71-380e-42dd-9312-0111d2bc0630}","prefs":[],"schema":1480349193877,"blockID":"i822","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1126353","who":"All Firefox users who have this add-on installed.","why":"This add-on appears to be malware, hiding itself in the Add-ons Manager, and keeping track of certain user actions.","name":"{6af08a71-380e-42dd-9312-0111d2bc0630} (malware)","created":"2015-01-27T09:50:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"96d0c12b-a6cf-4539-c1cf-a1c75c14ff24","last_modified":1480349198826},{"guid":"colmer@yopmail.com","prefs":[],"schema":1480349193877,"blockID":"i550","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=968445","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook accounts.","name":"Video Plugin Facebook (malware)","created":"2014-02-06T15:49:25Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c394d10b-384e-cbd0-f357-9c521715c373","last_modified":1480349198744},{"guid":"fplayer@adobe.flash","prefs":[],"schema":1480349193877,"blockID":"i444","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=909433","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware disguised as the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-08-26T14:49:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c6557989-1b59-72a9-da25-b816c4a4c723","last_modified":1480349198667},{"guid":"ascsurfingprotection@iobit.com","prefs":[],"schema":1480349193877,"blockID":"i740","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963776","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Advanced SystemCare Surfing Protection","created":"2014-10-17T15:39:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4405f99d-c9b7-c496-1b45-268163ce29b7","last_modified":1480349198637},{"guid":"{6E19037A-12E3-4295-8915-ED48BC341614}","prefs":[],"schema":1480349193877,"blockID":"i24","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=615518","who":"Users of RelevantKnowledge version 1.3.328.4 and older in Firefox 4 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"comScore RelevantKnowledge","created":"2011-03-02T17:42:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.3.328.4","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"7c189c5e-f95b-0aef-e9e3-8e879336503b","last_modified":1480349198606},{"guid":"crossriderapp4926@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i91","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=754648","who":"All Firefox users who have installed this add-on.","why":"Versions of this add-on prior to 0.81.44 automatically post message to users' walls and hide them from their view. Version 0.81.44 corrects this.","name":"Remove My Timeline (malware)","created":"2012-05-14T14:16:43Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.81.43","minVersion":"0","targetApplication":[]}],"id":"5ee3e72e-96fb-c150-fc50-dd581e960963","last_modified":1480349198547},{"guid":"/^(93abedcf-8e3a-4d02-b761-d1441e437c09@243f129d-aee2-42c2-bcd1-48858e1c22fd\\.com|9acfc440-ac2d-417a-a64c-f6f14653b712@09f9a966-9258-4b12-af32-da29bdcc28c5\\.com|58ad0086-1cfb-48bb-8ad2-33a8905572bc@5715d2be-69b9-4930-8f7e-64bdeb961cfd\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i544","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=949596","who":"All Firefox users who have this add-on installed. If you wish to continue using it, it can be enabled in the Add-ons Manager.","why":"This add-on is in violation of the Add-on Guidelines, using multiple add-on IDs and potentially doing other unwanted activities.","name":"SuperLyrics","created":"2014-01-30T11:51:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d8d25967-9814-3b65-0787-a0525c16e11e","last_modified":1480349198510},{"guid":"wHO@W9.net","prefs":[],"schema":1480349193877,"blockID":"i980","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1192468","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"BestSavEFOrYoU (malware)","created":"2015-08-11T11:20:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4beb917f-68f2-1f91-beed-dff6d83006f8","last_modified":1480349198483},{"guid":"frhegnejkgner@grhjgewfewf.com","prefs":[],"schema":1480349193877,"blockID":"i1040","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1212451","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Async Codec (malware)","created":"2015-10-07T13:03:37Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb6ab4ce-5517-bd68-2cf7-a93a109a528a","last_modified":1480349198458},{"guid":"firefox@luckyleap.net","prefs":[],"schema":1480349193877,"blockID":"i471","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:33Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3a9e04c7-5e64-6297-8442-2816915aad77","last_modified":1480349198433},{"guid":"auto-plugin-checker@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1210","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1270175","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on reports every visited URL to a third party without disclosing it to the user.","name":"auto-plugin-checker","created":"2016-05-04T16:25:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3e202419-5318-2025-b579-c828af24a06e","last_modified":1480349198401},{"guid":"lugcla21@gmail.com","prefs":[],"schema":1480349193877,"blockID":"i432","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=902072","who":"All Firefox users who have this add-on installed.","why":"This add-on includes malicious code that spams users' Facebook accounts with unwanted messages.","name":"FB Color Changer (malware)","created":"2013-08-06T13:16:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b6943f35-9429-1f8e-bf8e-fe37979fe183","last_modified":1480349198372},{"guid":"{99079a25-328f-4bd4-be04-00955acaa0a7}","prefs":[],"schema":1480349193877,"blockID":"i402","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=835678","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This group of add-ons is silently installed, bypassing our install opt-in screen. This violates our Add-on Guidelines.","name":"Searchqu","created":"2013-06-25T15:16:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"16008331-8b47-57c8-a6f7-989914d1cb8a","last_modified":1480349198341},{"guid":"{81b13b5d-fba1-49fd-9a6b-189483ac548a}","prefs":[],"schema":1480349193877,"blockID":"i473","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:43Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"76debc7b-b875-6da4-4342-1243cbe437f6","last_modified":1480349198317},{"guid":"{e935dd68-f90d-46a6-b89e-c4657534b353}","prefs":[],"schema":1480349193877,"blockID":"i732","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Sites Pro","created":"2014-10-16T16:38:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"97fdc235-ac1a-9f20-1b4a-17c2f0d89ad1","last_modified":1480349198260},{"guid":"{32da2f20-827d-40aa-a3b4-2fc4a294352e}","prefs":[],"schema":1480349193877,"blockID":"i748","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963787","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Start Page","created":"2014-10-17T16:02:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6c980c8e-4a3c-7912-4a3a-80add457575a","last_modified":1480349198223},{"guid":"chinaescapeone@facebook.com","prefs":[],"schema":1480349193877,"blockID":"i431","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=901770","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that uses a deceptive name and hijacks social networks.","name":"F-Secure Security Pack (malware)","created":"2013-08-05T16:43:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fbd89a9d-9c98-8481-e4cf-93e327ca8be1","last_modified":1480349198192},{"guid":"{cc6cc772-f121-49e0-b1f0-c26583cb0c5e}","prefs":[],"schema":1480349193877,"blockID":"i716","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Website Counselor","created":"2014-10-02T12:12:34Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"debcd28c-884b-ca42-d983-6fabf91034dd","last_modified":1480349198148},{"guid":"{906000a4-88d9-4d52-b209-7a772970d91f}","prefs":[],"schema":1480349193877,"blockID":"i474","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=935779","who":"All Firefox users who have this add-on installed.","why":"This add-on is part of a malicious Firefox installer bundle.","name":"Installer bundle (malware)","created":"2013-11-07T15:38:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"326d05b9-ace7-67c6-b094-aad926c185a5","last_modified":1480349197744},{"guid":"{A34CAF42-A3E3-11E5-945F-18C31D5D46B0}","prefs":["security.csp.enable","security.fileuri.strict_origin_policy","security.mixed_content.block_active_content"],"schema":1480349193877,"blockID":"i1227","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1274995","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on downgrades the security of all iframes from https to http and changes important Firefox security preferences.","name":"Mococheck WAP browser","created":"2016-05-31T15:45:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2230a5ce-a8f8-a20a-7974-3b960a03aba9","last_modified":1480349197699},{"guid":"{AB2CE124-6272-4b12-94A9-7303C7397BD1}","prefs":[],"schema":1480349193877,"blockID":"i20","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=627278","who":"Users of Skype extension versions below 5.2.0.7165 for all versions of Firefox.","why":"This add-on causes a high volume of Firefox crashes and introduces severe performance issues. Please update to the latest version. For more information, please read our announcement.","name":"Skype extension","created":"2011-01-20T18:39:25Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.2.0.7164","minVersion":"0.1","targetApplication":[]}],"id":"60e16015-1803-197a-3241-484aa961d18f","last_modified":1480349197667},{"guid":"f6682b47-e12f-400b-9bc0-43b3ccae69d1@39d6f481-b198-4349-9ebe-9a93a86f9267.com","prefs":[],"schema":1480349193877,"blockID":"i682","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1043017","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed, in violation of the Add-on Guidelines.","name":"enformation","created":"2014-08-04T16:07:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a7ae65cd-0869-67e8-02f8-6d22c56a83d4","last_modified":1480349197636},{"guid":"rally_toolbar_ff@bulletmedia.com","prefs":[],"schema":1480349193877,"blockID":"i537","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=950267","who":"All Firefox users who have this extension installed. If you want to continue using it, you can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by silently installing it.","name":"Rally Toolbar","created":"2014-01-23T15:51:48Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4ac6eb63-b51a-3296-5b02-bae77f424032","last_modified":1480349197604},{"guid":"x77IjS@xU.net","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i774","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1076771","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed and changes user settings without consent, in violation of the Add-on Guidelines\r\n","name":"YoutubeAdBlocke","created":"2014-10-31T16:22:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"4771da14-bcf2-19b1-3d71-bc61a1c7d457","last_modified":1480349197578},{"guid":"{49c53dce-afa0-49a1-a08b-2eb8e8444128}","prefs":[],"schema":1480349193877,"blockID":"i441","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844985","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed, violating our Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"ytbyclick","created":"2013-08-09T16:58:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5f08d720-58c2-6acb-78ad-7af45c82c90b","last_modified":1480349197550},{"guid":"searchengine@gmail.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i886","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1152555","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-on Manager.","why":"This add-on appears to be malware, being silently installed and hijacking user settings, in violation of the Add-on Guidelines.","name":"Search Enginer","created":"2015-04-10T16:25:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"46de4f6e-2b29-7334-ebbb-e0048f114f7b","last_modified":1480349197525},{"guid":"{bb7b7a60-f574-47c2-8a0b-4c56f2da9802}","prefs":[],"schema":1480349193877,"blockID":"i754","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080850","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"AdvanceElite","created":"2014-10-17T16:27:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f222ceb2-9b69-89d1-8dce-042d8131a12e","last_modified":1480349197500},{"guid":"/^(test3@test.org|test2@test.org|test@test.org|support@mozilla.org)$/","prefs":[],"schema":1480349193877,"blockID":"i1119","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1242721","who":"All users who have these add-ons installed.","why":"These add-ons are malicious, or at least attempts at being malicious, using misleading names and including risky code.","name":"test.org add-ons (malware)","created":"2016-01-25T13:31:43Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"afd2a0d7-b050-44c9-4e45-b63696d9b22f","last_modified":1480349197468},{"guid":"/^((34qEOefiyYtRJT@IM5Munavn\\.com)|(Mro5Fm1Qgrmq7B@ByrE69VQfZvZdeg\\.com)|(KtoY3KGxrCe5ie@yITPUzbBtsHWeCdPmGe\\.com)|(9NgIdLK5Dq4ZMwmRo6zk@FNt2GCCLGyUuOD\\.com)|(NNux7bWWW@RBWyXdnl6VGls3WAwi\\.com)|(E3wI2n@PEHTuuNVu\\.com)|(2d3VuWrG6JHBXbQdbr@3BmSnQL\\.com))$/","prefs":[],"schema":1480349193877,"blockID":"i324","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=841791","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:48:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5be3a399-af3e-644e-369d-628273b3fdc2","last_modified":1480349197432},{"guid":"axtara__web@axtara.com","prefs":[],"schema":1480349193877,"blockID":"i1263","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have version 1.1.1 or less of this add-on installed.","why":"Old versions of this add-on contained code from YouTube Unblocker, which was originally blocked due to malicious activity. Version 1.1.2 is now okay.","name":"AXTARA Search (pre 1.1.2)","created":"2016-08-17T16:47:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"1.1.1","minVersion":"0","targetApplication":[]}],"id":"c58be1c9-3d63-a948-219f-e3225e1eec8e","last_modified":1480349197404},{"guid":"{8f894ed3-0bf2-498e-a103-27ef6e88899f}","prefs":[],"schema":1480349193877,"blockID":"i792","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ExtraW","created":"2014-11-26T13:49:30Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bebc9e15-59a1-581d-0163-329d7414edff","last_modified":1480349197368},{"guid":"profsites@pr.com","prefs":[],"schema":1480349193877,"blockID":"i734","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.\r\n","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"ProfSites","created":"2014-10-16T16:39:26Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0d6d84d7-0b3f-c5ab-57cc-6b66b0775a23","last_modified":1480349197341},{"guid":"{872b5b88-9db5-4310-bdd0-ac189557e5f5}","prefs":[],"schema":1480349193877,"blockID":"i497","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=945530","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making settings changes that can't be easily reverted.","name":"DVDVideoSoft Menu","created":"2013-12-03T16:08:09Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e8da89c4-c585-77e4-9872-591d20723a7e","last_modified":1480349197240},{"guid":"123456789@offeringmedia.com","prefs":[],"schema":1480349193877,"blockID":"i664","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that attempts to hide itself by impersonating the Adobe Flash plugin.","name":"Taringa MP3 / Adobe Flash","created":"2014-07-10T15:41:24Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d0a7dda-d92a-c8e2-21be-c92b0a88ac8d","last_modified":1480349197208},{"guid":"firefoxdav@icloud.com","prefs":[],"schema":1480349193877,"blockID":"i1214","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1271358","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on is causing frequent and persistent crashing.","name":"iCloud Bookmarks","created":"2016-05-17T16:55:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.4.22","minVersion":"0","targetApplication":[]}],"id":"2dddd7a7-b081-45e2-3eeb-2a7f76a1465f","last_modified":1480349197172},{"guid":"youplayer@addons.mozilla.org","prefs":[],"schema":1480349193877,"blockID":"i660","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1036757","who":"All Firefox users who have this version of the add-on installed.","why":"Certain versions of the YouPlayer extension weren't developed by the original developer, and are likely malicious in nature. This violates the Add-on Guidelines for reusing an already existent ID.","name":"YouPlayer, versions between 79.9.8 and 208.0.1","created":"2014-07-10T15:31:04Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"208.0.1","minVersion":"79.9.8","targetApplication":[]}],"id":"82dca22b-b889-5d9d-3fc9-b2184851f2d1","last_modified":1480349197136},{"guid":"{df6bb2ec-333b-4267-8c4f-3f27dc8c6e07}","prefs":[],"schema":1480349193877,"blockID":"i487","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=940681","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Facebook 2013 (malware)","created":"2013-11-19T14:59:45Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5867c409-b342-121e-3c3b-426e2f0ba1d4","last_modified":1480349197109},{"guid":"/^({4e988b08-8c51-45c1-8d74-73e0c8724579}|{93ec97bf-fe43-4bca-a735-5c5d6a0a40c4}|{aed63b38-7428-4003-a052-ca6834d8bad3}|{0b5130a9-cc50-4ced-99d5-cda8cc12ae48}|{C4CFC0DE-134F-4466-B2A2-FF7C59A8BFAD})$/","prefs":[],"schema":1480349193877,"blockID":"i524","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947481","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"SweetPacks","created":"2013-12-20T13:43:21Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1a3a26a2-cdaa-e5ba-f6ac-47b98ae2cc26","last_modified":1480349197082},{"guid":"foxyproxy@eric.h.jung","prefs":[],"schema":1480349193877,"blockID":"i950","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1183890","who":"All users who have this add-on installed on Thunderbird 38 and above.","why":"This add-on is causing consistent startup crashes on Thunderbird 38 and above.","name":"FoxyProxy Standard for Thunderbird","created":"2015-07-15T09:34:44Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"4.5.5","minVersion":"0","targetApplication":[{"guid":"{3550f703-e582-4d05-9a08-453d09bdfdc6}","maxVersion":"*","minVersion":"38.0a2"},{"guid":"{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}","maxVersion":"*","minVersion":"2.35"}]}],"id":"5ee8203d-bea2-6cd5-9ba0-d1922ffb3d21","last_modified":1480349197056},{"guid":"{82AF8DCA-6DE9-405D-BD5E-43525BDAD38A}","prefs":[],"schema":1480349193877,"blockID":"i1056","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1225639","who":"All users who have this add-on installed in Firefox 43 and above. User who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is associated with frequent shutdown crashes in Firefox.","name":"Skype Click to Call","created":"2015-11-17T14:03:05Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.5.0.9082","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"43.0a1"}]}],"id":"484f8386-c415-7499-a8a0-f4e16f5a142f","last_modified":1480349197027},{"guid":"{22119944-ED35-4ab1-910B-E619EA06A115}","prefs":[],"schema":1480349193877,"blockID":"i45","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=699134","who":"Users of version 7.9.20.6 of RoboForm Toolbar and earlier on Firefox 48 and above.","why":"Older versions of the RoboForm Toolbar add-on are causing crashes in Firefox 48 and above. The developer has released a fix, available in versions 7.9.21+.","name":"Roboform","created":"2011-11-19T06:14:56Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"7.9.20.6","minVersion":"0.1","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"8.0a1"}]}],"id":"5f7f9e13-d3e8-ea74-8341-b83e36d67d94","last_modified":1480349196995},{"guid":"{87b5a11e-3b54-42d2-9102-0a7cb1f79ebf}","prefs":[],"schema":1480349193877,"blockID":"i838","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128327","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"Cyti Web (malware)","created":"2015-02-06T14:29:12Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1ba0e57c-4c0c-4eb6-26e7-c2016769c343","last_modified":1480349196965},{"guid":"/^({bf67a47c-ea97-4caf-a5e3-feeba5331231}|{24a0cfe1-f479-4b19-b627-a96bf1ea3a56})$/","prefs":[],"schema":1480349193877,"blockID":"i542","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963819","who":"All Firefox users who have this add-on installed.","why":"This add-on has been repeatedly blocked before and keeps showing up with new add-on IDs, in violation of the Add-on Guidelines.","name":"MixiDJ (malware)","created":"2014-01-28T14:10:49Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fc442b64-1b5d-bebb-c486-f431b154f3db","last_modified":1480349196622},{"guid":"/^({ebd898f8-fcf6-4694-bc3b-eabc7271eeb1}|{46008e0d-47ac-4daa-a02a-5eb69044431a}|{213c8ed6-1d78-4d8f-8729-25006aa86a76}|{fa23121f-ee7c-4bd8-8c06-123d087282c5}|{19803860-b306-423c-bbb5-f60a7d82cde5})$/","prefs":[],"schema":1480349193877,"blockID":"i622","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947482","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is known to change user settings without their consent, is distributed under multiple add-on IDs, and is also correlated with reports of tab functions being broken in Firefox, in violation of the Add-on Guidelines.","name":"WiseConvert","created":"2014-06-18T13:48:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"ffd184fa-aa8f-8a75-ff00-ce285dec5b22","last_modified":1480349196597},{"guid":"/^({fa95f577-07cb-4470-ac90-e843f5f83c52}|ffxtlbr@speedial\\.com)$/","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i696","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1031115","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using these add-ons can enable them in the Add-ons Manager.","why":"These add-ons are silently installed and change homepage and search defaults without user consent, in violation of the Add-on Guidelines. They are also distributed under more than one add-on ID.","name":"Speedial","created":"2014-08-21T13:55:41Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"130c7419-f727-a2fb-3891-627bc69a43bb","last_modified":1480349196565},{"guid":"pennerdu@faceobooks.ws","prefs":[],"schema":1480349193877,"blockID":"i442","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=904050","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that hijacks Facebook accounts.","name":"Console Video (malware)","created":"2013-08-13T14:00:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"fb83e48e-a780-9d06-132c-9ecc65b43674","last_modified":1480349196541},{"guid":"anttoolbar@ant.com","prefs":[],"schema":1480349193877,"blockID":"i88","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=748269","who":"All Firefox users who have installed version 2.4.6.4 of the Ant Video Downloader and Player add-on.","why":"Version 2.4.6.4 of the Ant Video Downloader and Player add-on is causing a very high number of crashes in Firefox. There's an updated version 2.4.6.5 that doesn't have this problem. All users are recommended to update as soon as possible.","name":"Ant Video Downloader and Player","created":"2012-05-01T10:32:11Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"2.4.6.4","minVersion":"2.4.6.4","targetApplication":[]}],"id":"9eef435b-39d4-2b73-0810-44b0d3ff52ad","last_modified":1480349196509},{"guid":"{E90FA778-C2B7-41D0-9FA9-3FEC1CA54D66}","prefs":[],"schema":1480349193877,"blockID":"i446","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=788838","who":"All Firefox users who have this add-on installed. The add-on can be enabled again in the Add-ons Manager.","why":"This add-on is installed silently, in violation of our Add-on Guidelines.","name":"YouTube to MP3 Converter","created":"2013-09-06T15:59:29Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"83eb6337-a3b6-84e4-e76c-ee9200b80796","last_modified":1480349196471},{"guid":"{ad7ce998-a77b-4062-9ffb-1d0b7cb23183}","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i804","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1080839","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and is considered malware, in violation of the Add-on Guidelines.","name":"Astromenda Search Addon","created":"2014-12-15T10:53:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"633f9999-c81e-bd7a-e756-de7d34feb39d","last_modified":1480349196438},{"guid":"{52b0f3db-f988-4788-b9dc-861d016f4487}","prefs":[],"schema":1480349193877,"blockID":"i584","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=974104","who":"All Firefox users who have these add-ons installed. If you wish to continue using these add-ons, you can enable them in the Add-ons Manager.","why":"Versions of this add-on are silently installed by the Free Driver Scout installer, in violation of our Add-on Guidelines.","name":"Web Check (Free Driver Scout bundle)","created":"2014-05-22T11:07:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"0.1.9999999","minVersion":"0","targetApplication":[]}],"id":"cba0ac44-90f9-eabb-60b0-8da2b645e067","last_modified":1480349196363},{"guid":"dodatek@flash2.pl","prefs":[],"schema":1480349193877,"blockID":"i1279","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"Any user with version 1.3 or newer of this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja Flash WORK addon","created":"2016-10-27T15:52:00Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"1.3","targetApplication":[]}],"id":"2dab5211-f9ec-a1bf-c617-6f94f28b5ee1","last_modified":1480349196331},{"guid":"{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}","prefs":[],"schema":1480349193877,"blockID":"i440","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=903647","who":"All Firefox users who have this add-on installed.","why":"This add-on is installed silently and doesn't follow many other of the Add-on Guidelines. If you want to continue using this add-on, you can enable it in the Add-ons Manager.","name":"GlitterFun","created":"2013-08-09T16:26:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3f77f3c-b1d6-3b29-730a-846007b9cb16","last_modified":1480349196294},{"guid":"xivars@aol.com","prefs":[],"schema":1480349193877,"blockID":"i501","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=946420","who":"All Firefox users who have this add-on installed.","why":"This is a malicious Firefox extension that uses a deceptive name and hijacks users' Facebook accounts.","name":"Video Plugin Facebook (malware)","created":"2013-12-04T15:34:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3303d201-7006-3c0d-5fd5-45503e2e690c","last_modified":1480349196247},{"guid":"2bbadf1f-a5af-499f-9642-9942fcdb7c76@f05a14cc-8842-4eee-be17-744677a917ed.com","prefs":[],"schema":1480349193877,"blockID":"i700","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1052599","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is widely considered malware and is apparently installed silently into users' systems, in violation of the Add-on Guidelines.","name":"PIX Image Viewer","created":"2014-08-21T16:15:16Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1b72889b-90e6-ea58-4fe8-d48257df7d8b","last_modified":1480349196212},{"guid":"/^[0-9a-f]+@[0-9a-f]+\\.info/","prefs":[],"schema":1480349193877,"blockID":"i256","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806451","who":"All Firefox users who have installed any of these add-ons.","why":"The set of extensions labeled as Codec, Codec-M, Codec-C and other names are malware being distributed as genuine add-ons.\r\n\r\nIf you think an add-on you installed was incorrectly blocked and the block dialog pointed you to this page, please comment on this blog post.","name":"Codec extensions (malware)","created":"2013-01-22T12:16:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"0c654540-00f2-0ad4-c9be-7ca2ace5341e","last_modified":1480349196184},{"guid":"toolbar@ask.com","prefs":[],"schema":1480349193877,"blockID":"i600","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1024719","who":"All Firefox users who have these versions of the Ask Toolbar installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"Certain old versions of the Ask Toolbar are causing problems to users when trying to open new tabs. Using more recent versions of the Ask Toolbar should also fix this problem.","name":"Ask Toolbar (old Avira Security Toolbar bundle)","created":"2014-06-12T14:16:08Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"3.15.5.*","minVersion":"3.15.5","targetApplication":[]}],"id":"51c4ab3b-9ad3-c5c3-98c8-a220025fc5a3","last_modified":1480349196158},{"guid":"{729c9605-0626-4792-9584-4cbe65b243e6}","prefs":[],"schema":1480349193877,"blockID":"i788","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Browser Ext Assistance","created":"2014-11-20T10:07:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3c588238-2501-6a53-65ea-5c8ff0f3e51d","last_modified":1480349196123},{"guid":"unblocker20__web@unblocker.yt","prefs":[],"schema":1480349193877,"blockID":"i1213","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 2.0","created":"2016-05-09T17:28:18Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"de305335-e9f3-f410-cf5c-f88b7ad4b088","last_modified":1480349196088},{"guid":"webbooster@iminent.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i630","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=866943","who":"All Firefox users who have any of these add-ons installed. Users who wish to continue using them can enable them in the Add-ons Manager.","why":"These add-ons have been silently installed repeatedly, and change settings without user consent, in violation of the Add-on Guidelines.","name":"Iminent Minibar","created":"2014-06-26T15:49:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d894ea79-8215-7a0c-b0e9-be328c3afceb","last_modified":1480349196032},{"guid":"jid1-uabu5A9hduqzCw@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1016","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1208051","who":"All users who have this add-on installed.","why":"This add-on is injecting unwanted and unexpected advertisements into all web pages, and masking this behavior as ad-blocking in its code.","name":"SpeedFox (malware)","created":"2015-09-24T09:49:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"31397419-3dfa-9db3-f1aa-e812d4220669","last_modified":1480349196001},{"guid":"/^firefox@(jumpflip|webconnect|browsesmart|mybuzzsearch|outobox|greygray|lemurleap|divapton|secretsauce|batbrowse|whilokii|linkswift|qualitink|browsefox|kozaka|diamondata|glindorus|saltarsmart|bizzybolt|websparkle)\\.(com?|net|org|info|biz)$/","prefs":[],"schema":1480349193877,"blockID":"i548","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=937405","who":"All Firefox users who have one or more of these add-ons installed. If you wish to continue using any of these add-ons, they can be enabled in the Add-ons Manager.","why":"A large amount of add-ons developed by Yontoo are known to be silently installed and otherwise violate the Add-on Guidelines.","name":"Yontoo add-ons","created":"2014-01-30T15:06:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bfaf3510-397e-48e6-cc4f-74202aaaed54","last_modified":1480349195955},{"guid":"firefox@bandoo.com","prefs":[],"schema":1480349193877,"blockID":"i23","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=629634","who":"Users of Bandoo version 5.0 for Firefox 3.6 and later.","why":"This add-on causes a high volume of Firefox crashes.","name":"Bandoo","created":"2011-03-01T23:30:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"5.0","minVersion":"5.0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"3.7a1pre"}]}],"id":"bd487cf4-3f6a-f956-a6e9-842ac8deeac5","last_modified":1480349195915},{"guid":"5nc3QHFgcb@r06Ws9gvNNVRfH.com","prefs":[],"schema":1480349193877,"blockID":"i372","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=875752","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware pretending to be the Flash Player plugin.","name":"Flash Player 11 (malware)","created":"2013-06-18T13:23:40Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"dc71fcf5-fae4-5a5f-6455-ca7bbe4202db","last_modified":1480349195887},{"guid":"/^(7tG@zEb\\.net|ru@gfK0J\\.edu)$/","prefs":[],"schema":1480349193877,"blockID":"i854","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=952255","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"youtubeadblocker (malware)","created":"2015-02-09T15:41:36Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"cfe42207-67a9-9b88-f80c-994e6bdd0c55","last_modified":1480349195851},{"guid":"{a7aae4f0-bc2e-a0dd-fb8d-68ce32c9261f}","prefs":[],"schema":1480349193877,"blockID":"i378","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=865090","who":"All Firefox users who have installed this add-on.","why":"This extension is malware that hijacks Facebook accounts for malicious purposes.","name":"Myanmar Extension for Facebook (malware)","created":"2013-06-18T15:58:54Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"30ecd9b9-4023-d9ef-812d-f1a75bb189b0","last_modified":1480349195823},{"guid":"a88a77ahjjfjakckmmabsy278djasi@jetpack","prefs":[],"schema":1480349193877,"blockID":"i1034","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1211171","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Fast Unlock (malware)","created":"2015-10-05T16:28:48Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f801f112-3e8f-770f-10db-384349a36026","last_modified":1480349195798},{"guid":"crossriderapp5060@crossrider.com","prefs":[],"schema":1480349193877,"blockID":"i228","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=810016","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently side-installed by other software, and it overrides user preferences and inserts advertisements in web content.","name":"Savings Sidekick","created":"2012-11-29T16:31:13Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a37f76ac-7b77-b5a3-bac8-addaacf34bae","last_modified":1480349195769},{"guid":"/^(saamazon@mybrowserbar\\.com)|(saebay@mybrowserbar\\.com)$/","prefs":[],"schema":1480349193877,"blockID":"i672","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011337","who":"All Firefox users who have these add-ons installed. Users wishing to continue using these add-ons can enable them in the Add-ons Manager.","why":"These add-ons are being silently installed, in violation of the Add-on Guidelines.","name":"Spigot Shopping Assistant","created":"2014-07-22T15:13:57Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e072a461-ee5a-c83d-8d4e-5686eb585a15","last_modified":1480349195347},{"guid":"{b99c8534-7800-48fa-bd71-519a46cdc7e1}","prefs":[],"schema":1480349193877,"blockID":"i596","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1011325","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed, in violation with our Add-on Guidelines.","name":"BrowseMark","created":"2014-06-12T13:19:59Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f411bb0f-7c82-9061-4a80-cabc8ff45beb","last_modified":1480349195319},{"guid":"/^({94d62e35-4b43-494c-bf52-ba5935df36ef}|firefox@advanceelite\\.com|{bb7b7a60-f574-47c2-8a0b-4c56f2da9802})$/","prefs":[],"schema":1480349193877,"blockID":"i856","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1130323","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"AdvanceElite (malware)","created":"2015-02-09T15:51:11Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e3d52650-d3e2-4cef-71f7-e6188f56fe4d","last_modified":1480349195286},{"guid":"{458fb825-2370-4973-bf66-9d7142141847}","prefs":["app.update.auto","app.update.enabled","app.update.interval","app.update.url"],"schema":1480349193877,"blockID":"i1024","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1209588","who":"All users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on hides itself in the Add-ons Manager, interrupts the Firefox update process, and reportedly causes other problems to users, in violation of the Add-on Guidelines.","name":"Web Shield","created":"2015-09-29T09:25:27Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"32c5baa7-d547-eaab-302d-b873c83bfe2d","last_modified":1480349195258},{"guid":"{f2456568-e603-43db-8838-ffa7c4a685c7}","prefs":[],"schema":1480349193877,"blockID":"i778","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Sup-SW","created":"2014-11-07T13:53:13Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"93568fa2-0cb7-4e1d-e893-d7261e81547c","last_modified":1480349195215},{"guid":"{77BEC163-D389-42c1-91A4-C758846296A5}","prefs":[],"schema":1480349193877,"blockID":"i566","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=964594","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-on Manager.","why":"This add-on is silently installed into Firefox, in violation of the Add-on Guidelines.","name":"V-Bates","created":"2014-03-05T13:20:54Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"080edbac-25d6-e608-abdd-feb1ce7a9a77","last_modified":1480349195185},{"guid":"helper@vidscrab.com","prefs":[],"schema":1480349193877,"blockID":"i1077","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1231010","who":"All Firefox users who have this add-on installed. Users who wish to continue using the add-on can enable it in the Add-ons Manager.","why":"This add-on injects remote scripts and injects unwanted content into web pages.","name":"YouTube Video Downloader (from AddonCrop)","created":"2016-01-14T14:32:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"36b2e1e0-5fda-bde3-db55-dfcbe24dfd04","last_modified":1480349195157},{"guid":"/^ext@WebexpEnhancedV1alpha[0-9]+\\.net$/","prefs":[],"schema":1480349193877,"blockID":"i535","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=952717","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, it can be enabled in the Add-ons Manager.","why":"This add-on is generally unwanted by users and uses multiple random IDs in violation of the Add-on Guidelines.","name":"Webexp Enhanced","created":"2014-01-09T11:22:19Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c7d6a30d-f3ee-40fb-5256-138dd4593a61","last_modified":1480349195123},{"guid":"jid1-XLjasWL55iEE1Q@jetpack","prefs":[],"schema":1480349193877,"blockID":"i578","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1002037","who":"All Firefox users who have this add-on installed.","why":"This is a malicious add-on that presents itself as \"Flash Player\" but is really injecting unwanted content into Facebook pages.","name":"Flash Player (malware)","created":"2014-04-28T16:25:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"1e75b2f0-02fc-77a4-ad2f-52a4caff1a71","last_modified":1480349195058},{"guid":"{a3a5c777-f583-4fef-9380-ab4add1bc2a8}","prefs":[],"schema":1480349193877,"blockID":"i142","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=792132","who":"Todos los usuarios de Firefox que instalaron la versi\u00f3n 4.2 del complemento Cuevana Stream.\r\n\r\nAll Firefox users who have installed version 4.2 of the Cuevana Stream add-on.","why":"Espa\u00f1ol\r\nUna versi\u00f3n maliciosa del complemento Cuevana Stream (4.2) fue colocada en el sitio Cuevana y distribuida a muchos usuarios del sitio. Esta versi\u00f3n recopila informaci\u00f3n de formularios web y los env\u00eda a una direcci\u00f3n remota con fines maliciosos. Se le recomienda a todos los usuarios que instalaron esta versi\u00f3n que cambien sus contrase\u00f1as inmediatamente, y que se actualicen a la nueva versi\u00f3n segura, que es la 4.3.\r\n\r\nEnglish\r\nA malicious version of the Cuevana Stream add-on (4.2) was uploaded to the Cuevana website and distributed to many of its users. This version takes form data and sends it to a remote location with malicious intent. It is recommended that all users who installed this version to update their passwords immediately, and update to the new safe version, version 4.3.\r\n\r\n","name":"Cuevana Stream (malicious version)","created":"2012-09-18T13:37:47Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"4.2","minVersion":"4.2","targetApplication":[]}],"id":"91e551b9-7e94-60e2-f1bd-52f25844ab16","last_modified":1480349195007},{"guid":"{34712C68-7391-4c47-94F3-8F88D49AD632}","prefs":[],"schema":1480349193877,"blockID":"i922","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1173154","who":"All Firefox users who have this add-on installed in Firefox 39 and above.\r\n","why":"Certain versions of this extension are causing startup crashes in Firefox 39 and above.\r\n","name":"RealPlayer Browser Record Plugin","created":"2015-06-09T15:27:31Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"39.0a1"}]}],"id":"dd350efb-34ac-2bb5-5afd-eed722dbb916","last_modified":1480349194976},{"guid":"PDVDZDW52397720@XDDWJXW57740856.com","prefs":["browser.startup.homepage","browser.search.defaultenginename"],"schema":1480349193877,"blockID":"i846","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128320","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and attempts to change user settings like the home page and default search, in violation of the Add-on Guidelines.","name":"Ge-Force","created":"2015-02-06T15:03:39Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c33e950c-c977-ed89-c86a-3be8c4be1967","last_modified":1480349194949},{"guid":"{977f3b97-5461-4346-92c8-a14c749b77c9}","prefs":[],"schema":1480349193877,"blockID":"i69","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=729356","who":"All Firefox users who have this add-on installed.","why":"This add-on adds apps to users' accounts, with full access permissions, and sends spam posts using these apps, all without any consent from users.","name":"Zuperface+","created":"2012-02-22T16:41:23Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f105bdc7-7ebd-587c-6344-1533249f50b3","last_modified":1480349194919},{"guid":"discoverypro@discoverypro.com","prefs":[],"schema":1480349193877,"blockID":"i582","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1004231","who":"All Firefox users who have this add-on installed. If you wish to continue using this add-on, you can enabled it in the Add-ons Manager.","why":"This add-on is silently installed by the CNET installer for MP3 Rocket and probably other software packages. This is in violation of the Add-on Guidelines.","name":"Website Discovery Pro","created":"2014-04-30T16:10:03Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"34eab242-6fbc-a459-a89e-0dc1a0b8355d","last_modified":1480349194878},{"guid":"jid1-bKSXgRwy1UQeRA@jetpack","prefs":[],"schema":1480349193877,"blockID":"i680","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=979856","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into user's systems, in violation of the Add-on Guidelines.","name":"Trusted Shopper","created":"2014-08-01T16:34:01Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f701b790-b266-c69d-0fba-f2d189cb0f34","last_modified":1480349194851},{"guid":"bcVX5@nQm9l.org","prefs":[],"schema":1480349193877,"blockID":"i848","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128266","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"boomdeal","created":"2015-02-09T15:21:17Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"f8d6d4e1-b9e6-07f5-2b49-192106a45d82","last_modified":1480349194799},{"guid":"aytac@abc.com","prefs":[],"schema":1480349193877,"blockID":"i504","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947341","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks users' Facebook accounts.","name":"Facebook Haber (malware)","created":"2013-12-06T12:07:58Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"bfaf8298-dd69-165c-e1ed-ad55584abd18","last_modified":1480349194724},{"guid":"Adobe@flash.com","prefs":[],"schema":1480349193877,"blockID":"i136","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=790100","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware posing as a legitimate Adobe product.","name":"Adobe Flash (malware)","created":"2012-09-10T16:09:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"47ac744e-3176-5cb6-1d02-b460e0c7ada0","last_modified":1480349194647},{"guid":"{515b2424-5911-40bd-8a2c-bdb20286d8f5}","prefs":[],"schema":1480349193877,"blockID":"i491","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=940753","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted.","name":"Connect DLC","created":"2013-11-29T14:52:24Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"6d658443-b34a-67ad-934e-cbf7cd407460","last_modified":1480349194580},{"guid":"/^({3f3cddf8-f74d-430c-bd19-d2c9147aed3d}|{515b2424-5911-40bd-8a2c-bdb20286d8f5}|{17464f93-137e-4646-a0c6-0dc13faf0113}|{d1b5aad5-d1ae-4b20-88b1-feeaeb4c1ebc}|{aad50c91-b136-49d9-8b30-0e8d3ead63d0})$/","prefs":[],"schema":1480349193877,"blockID":"i516","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947478","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by making changes that can't be easily reverted and being distributed under multiple add-on IDs.","name":"Connect DLC","created":"2013-12-20T12:38:20Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"96f8e157-8b8b-8e2e-76cd-6850599b4370","last_modified":1480349194521},{"guid":"wxtui502n2xce9j@no14","prefs":[],"schema":1480349193877,"blockID":"i1012","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1206157","who":"All users who have this add-on installed.","why":"This is a malicious add-on that takes over Facebook accounts.","name":"Video fix (malware)","created":"2015-09-21T13:04:09Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"246798ac-25fa-f4a4-258c-a71f9f6ae091","last_modified":1480349194463},{"guid":"flashX@adobe.com","prefs":[],"schema":1480349193877,"blockID":"i168","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=807052","who":"All Firefox users who have this add-on installed.","why":"This is an exploit proof-of-concept created for a conference presentation, which will probably be copied and modified for malicious purposes. \r\n","name":"Zombie Browser Pack","created":"2012-10-30T12:07:41Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d7c69812-801c-8d8e-12cb-c5171bdc48a1","last_modified":1480349194428},{"guid":"/^(ff\\-)?dodate(kKKK|XkKKK|k|kk|kkx|kR)@(firefox|flash(1)?)\\.pl|dode(ee)?k@firefoxnet\\.pl|(addon|1)@upsolutions\\.pl$/","prefs":[],"schema":1480349193877,"blockID":"i1278","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"Any user with a version of this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja dodatku Flash Add-on","created":"2016-10-27T10:52:53Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"389aec65-a15d-8276-c7a8-691ac283c9f1","last_modified":1480349194386},{"guid":"tmbepff@trendmicro.com","prefs":[],"schema":1480349193877,"blockID":"i1223","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1275245","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"Add-on is causing a high-frequency crash in Firefox.","name":"Trend Micro BEP 9.2 to 9.2.0.1023","created":"2016-05-30T17:07:04Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"9.2.0.1023","minVersion":"9.2","targetApplication":[]}],"id":"46f75b67-2675-bdde-be93-7ea03475d405","last_modified":1480349194331},{"guid":"{4889ddce-7a83-45e6-afc9-1e4f1149fff4}","prefs":[],"schema":1480343836083,"blockID":"i840","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1128327","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed and performs unwanted actions, in violation of the Add-on Guidelines.","name":"Cyti Web (malware)","created":"2015-02-06T14:30:06Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"be600f35-0633-29f3-c571-819e19d85db9","last_modified":1480349193867},{"guid":"{55dce8ba-9dec-4013-937e-adbf9317d990","prefs":[],"schema":1480343836083,"blockID":"i690","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1048647","who":"All Firefox users. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed in users' systems, in violation of the Add-on Guidelines.","name":"Deal Keeper","created":"2014-08-12T16:23:46Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"512b0d40-a10a-5ddc-963b-b9c487eb1422","last_modified":1480349193833},{"guid":"/^new@kuot\\.pro|{13ec6687-0b15-4f01-a5a0-7a891c18e4ee}|rebeccahoppkins(ty(tr)?)?@gmail\\.com|{501815af-725e-45be-b0f2-8f36f5617afc}|{9bdb5f1f-b1e1-4a75-be31-bdcaace20a99}|{e9d93e1d-792f-4f95-b738-7adb0e853b7b}|dojadewaskurwa@gmail\\.com$/","prefs":[],"schema":1480343836083,"blockID":"i1414","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1312748","who":"All users who have this add-on installed.","why":"This add-on claims to be a flash plugin and it does some work on youtube, but it also steals your facebook and adfly credentials and sends them to a remote server.","name":"Aktualizacja dodatku Flash (malware)","created":"2016-10-28T18:06:03Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"5cebc983-bc88-d5f8-6807-bd1cbfcd82fd","last_modified":1480349193798},{"guid":"/^pink@.*\\.info$/","prefs":[],"schema":1480343836083,"blockID":"i238","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=806543","who":"All Firefox users (Firefox 19 and above) who have any of these add-ons installed.","why":"This is a set of malicious add-ons that affect many users and are installed without their consent.","name":"Pink add-ons (malware)","created":"2012-12-07T13:46:20Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[{"guid":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","maxVersion":"*","minVersion":"18.0"}]}],"id":"0d964264-8bd6-b78d-3c6c-92046c7dc8d0","last_modified":1480349193764},{"guid":"{58d2a791-6199-482f-a9aa-9b725ec61362}","prefs":[],"schema":1480343836083,"blockID":"i746","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=963787","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' systems, in violation of the Add-on Guidelines.","name":"Start Page","created":"2014-10-17T16:01:53Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"8ebbc7d0-635c-b74a-de9f-16eb5837b36a","last_modified":1480349193730},{"guid":"{94cd2cc3-083f-49ba-a218-4cda4b4829fd}","prefs":[],"schema":1480343836083,"blockID":"i590","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1013678","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is silently installed into users' profiles, in violation of the Add-on Guidelines.","name":"Value Apps","created":"2014-06-03T16:12:50Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"556b8d4d-d6c2-199d-9f33-8eccca07e8e7","last_modified":1480349193649},{"guid":"contentarget@maildrop.cc","prefs":[],"schema":1480343836083,"blockID":"i818","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119971","who":"All Firefox users who have this add-on installed.","why":"This is a malicious extension that hijacks Facebook accounts.","name":"Astro Play (malware)","created":"2015-01-12T09:29:19Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"440e9923-027a-6089-e036-2f78937dc193","last_modified":1480349193622},{"guid":"unblocker30__web@unblocker.yt","prefs":[],"schema":1480343836083,"blockID":"i1228","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"This add-on is a copy of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker 3.0","created":"2016-06-01T15:17:22Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"2d83e640-ef9d-f260-f5a3-a1a5c8390bfc","last_modified":1480349193595},{"guid":"noOpus@outlook.com","prefs":[],"schema":1480343836083,"blockID":"i816","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1119659","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems without their consent and performs unwanted operations.","name":"Full Screen (malware)","created":"2015-01-09T12:52:32Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b64d7cef-8b6c-2575-16bc-732fca7db377","last_modified":1480349193537},{"guid":"{c95a4e8e-816d-4655-8c79-d736da1adb6d}","prefs":[],"schema":1480343836083,"blockID":"i433","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=844945","who":"All Firefox users who have this add-on installed.","why":"This add-on bypasses the external install opt in screen in Firefox, violating the Add-on Guidelines. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","name":"Hotspot Shield","created":"2013-08-09T11:25:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b3168278-a8ae-4882-7f26-355bc362bed0","last_modified":1480349193510},{"guid":"{9802047e-5a84-4da3-b103-c55995d147d1}","prefs":[],"schema":1480343836083,"blockID":"i722","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1073810","who":"All Firefox users who have this add-on installed.","why":"This add-on is silently installed into users' systems. It uses very unsafe practices to load its code, and leaks information of all web browsing activity. These are all violations of the Add-on Guidelines.","name":"Web Finder Pro","created":"2014-10-07T12:58:14Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"50097c29-26b1-bf45-ffe1-83da217eb127","last_modified":1480349193482},{"guid":"/^({bf9194c2-b86d-4ebc-9b53-1c08b6ff779e}|{61a83e16-7198-49c6-8874-3e4e8faeb4f3}|{f0af464e-5167-45cf-9cf0-66b396d1918c}|{5d9968c3-101c-4944-ba71-72d77393322d}|{01e86e69-a2f8-48a0-b068-83869bdba3d0})$/","prefs":[],"schema":1480343836083,"blockID":"i515","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=947473","who":"All Firefox users who have this add-on installed. Users who wish to continue using it can enable it in the Add-ons Manager.","why":"The installer that includes this add-on violates the Add-on Guidelines by using multiple add-on IDs and making unwanted settings changes.","name":"VisualBee Toolbar","created":"2013-12-20T12:26:49Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"029fa6f9-2351-40b7-5443-9a66e057f199","last_modified":1480349193449},{"guid":"/^({d50bfa5f-291d-48a8-909c-5f1a77b31948}|{d54bc985-6e7b-46cd-ad72-a4a266ad879e}|{d89e5de3-5543-4363-b320-a98cf150f86a}|{f3465017-6f51-4980-84a5-7bee2f961eba}|{fae25f38-ff55-46ea-888f-03b49aaf8812})$/","prefs":[],"schema":1480343836083,"blockID":"i1137","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251940","who":"All users who have this add-on installed.","why":"This is a malicious add-on that hides itself from view and disables various security features in Firefox.","name":"Watcher (malware)","created":"2016-03-04T17:56:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"252e18d0-85bc-7bb3-6197-5f126424c9b3","last_modified":1480349193419},{"guid":"ffxtlbr@claro.com","prefs":[],"schema":1480343836083,"blockID":"i218","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=816762","who":"All Firefox users who have installed this add-on.","why":"The Claro Toolbar is side-installed with other software, unexpectedly changing users' settings and then making it impossible for these settings to be reverted by users.","name":"Claro Toolbar","created":"2012-11-29T16:07:00Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"e017a3b2-9b37-b8a0-21b0-bc412ae8a7f4","last_modified":1480349193385},{"guid":"/^(.*@(unblocker\\.yt|sparpilot\\.com))|(axtara@axtara\\.com)$/","prefs":[],"schema":1480343836083,"blockID":"i1229","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1251911","who":"All users who have this add-on installed.","why":"These add-ons are copies of YouTube Unblocker, which was originally blocked due to malicious activity.","name":"YouTube Unblocker (various)","created":"2016-06-03T15:28:39Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"c677cc5d-5b1e-8aa2-5cea-5a8dddce2ecf","last_modified":1480349193344},{"guid":"/^(j003-lqgrmgpcekslhg|SupraSavings|j003-dkqonnnthqjnkq|j003-kaggrpmirxjpzh)@jetpack$/","prefs":[],"schema":1480343836083,"blockID":"i692","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1048656","who":"All Firefox users who have this add-on installed. Users who wish to continue using this add-on can enable it in the Add-ons Manager.","why":"This add-on is being silently installed in users' systems, in violation of the Add-on Guidelines.","name":"SupraSavings","created":"2014-08-12T16:27:06Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"b0d30256-4581-1489-c241-d2e85b6c38f4","last_modified":1480349193295},{"guid":"helperbar@helperbar.com","prefs":[],"schema":1480343836083,"blockID":"i258","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=817786","who":"All Firefox users who have this add-on installed. This only applies to version 1.0 of Snap.do. Version 1.1 fixed all the issues for which this block was created.","why":"This extension violates a number of our Add-on Guidelines, particularly on installation and settings handling. It also causes some stability problems in Firefox due to the way the toolbar is handled.\r\n\r\nUsers who wish to keep the add-on enabled can enable it again in the Add-ons Manager.","name":"Snap.do","created":"2013-01-28T13:52:26Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"1.0","minVersion":"0","targetApplication":[]}],"id":"f1ede5b8-7757-5ec5-d8ed-1a01889154aa","last_modified":1480349193254},{"guid":"/^((support2_en@adobe14\\.com)|(XN4Xgjw7n4@yUWgc\\.com)|(C7yFVpIP@WeolS3acxgS\\.com)|(Kbeu4h0z@yNb7QAz7jrYKiiTQ3\\.com)|(aWQzX@a6z4gWdPu8FF\\.com)|(CBSoqAJLYpCbjTP90@JoV0VMywCjsm75Y0toAd\\.com)|(zZ2jWZ1H22Jb5NdELHS@o0jQVWZkY1gx1\\.com))$/","prefs":[],"schema":1480343836083,"blockID":"i326","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=841791","who":"All users who have this add-on installed.","why":"This extension is malware, installed pretending to be the Flash Player plugin.","name":"Flash Player (malware)","created":"2013-03-22T14:49:08Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"3142020b-8af9-1bac-60c5-ce5ad0ff3d42","last_modified":1480349193166},{"guid":"newmoz@facebook.com","prefs":[],"schema":1480343836083,"blockID":"i576","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=997986","who":"All Firefox users who have this add-on installed.","why":"This add-on is malware that hijacks Facebook user accounts and sends spam on the user's behalf.","name":"Facebook Service Pack (malware)","created":"2014-04-22T14:34:42Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"d85798d3-9b87-5dd9-ace2-64914b93df77","last_modified":1480349193114},{"guid":"flvto@hotger.com","prefs":[],"schema":1480343836083,"blockID":"i1211","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=1270175","who":"All users of this add-on. If you wish to continue using it, you can enable it in the Add-ons Manager.","why":"This add-on reports every visited URL to a third party without disclosing it to the user.","name":"YouTube to MP3 Button","created":"2016-05-04T16:26:32Z"},"enabled":true,"versionRange":[{"severity":1,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"a14d355f-719f-3b97-506c-083cc97cebaa","last_modified":1480349193088},{"guid":"{0F827075-B026-42F3-885D-98981EE7B1AE}","prefs":[],"schema":1480343836083,"blockID":"i334","details":{"bug":"https://bugzilla.mozilla.org/show_bug.cgi?id=862272","who":"All Firefox users who have this extension installed.","why":"This extension is malicious and is installed under false pretenses, causing problems for many Firefox users. Note that this is not the same BrowserProtect extension that is listed on our add-ons site. That one is safe to use.","name":"Browser Protect / bProtector (malware)","created":"2013-04-16T13:25:01Z"},"enabled":true,"versionRange":[{"severity":3,"maxVersion":"*","minVersion":"0","targetApplication":[]}],"id":"aad4545f-8f9d-dd53-2aa8-e8945cad6185","last_modified":1480349192987}]} \ No newline at end of file From 917492cdcfed7b788160f041c7593aa192a86f9a Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Fri, 1 Jun 2018 04:55:48 -0400 Subject: [PATCH 036/116] Bug 1466062 - Update Debugger Frontend v62. r=jdescottes --- devtools/client/debugger/new/README.mozilla | 4 +- .../client/debugger/new/dist/debugger.css | 62 +++++++++---------- .../new/src/components/Editor/index.js | 3 +- .../components/PrimaryPanes/SourcesTree.js | 8 ++- .../SecondaryPanes/Breakpoints/Breakpoint.js | 8 +-- .../SecondaryPanes/Breakpoints/index.js | 3 +- .../debugger/new/src/utils/editor/index.js | 29 +++------ .../new/src/utils/editor/source-editor.js | 4 ++ devtools/client/sourceeditor/editor.js | 9 +++ 9 files changed, 66 insertions(+), 64 deletions(-) diff --git a/devtools/client/debugger/new/README.mozilla b/devtools/client/debugger/new/README.mozilla index 1ab45107f77f..3afd009d6ce6 100644 --- a/devtools/client/debugger/new/README.mozilla +++ b/devtools/client/debugger/new/README.mozilla @@ -1,9 +1,9 @@ This is the debugger.html project output. See https://github.com/devtools-html/debugger.html -Version 61 +Version 62 -Comparison: https://github.com/devtools-html/debugger.html/compare/release-60...release-61 +Comparison: https://github.com/devtools-html/debugger.html/compare/release-61...release-62 Packages: - babel-plugin-transform-es2015-modules-commonjs @6.26.2 diff --git a/devtools/client/debugger/new/dist/debugger.css b/devtools/client/debugger/new/dist/debugger.css index 60f5436b443a..01089fba742b 100644 --- a/devtools/client/debugger/new/dist/debugger.css +++ b/devtools/client/debugger/new/dist/debugger.css @@ -1759,6 +1759,37 @@ menuseparator { .function-signature .comma { color: var(--object-color); } +.source-icon { + position: relative; + background-color: var(--theme-comment); + mask-size: 100%; + display: inline-block; + margin-inline-end: 5px; +} + +.source-icon, +.source-icon svg { + width: 15px; + height: 15px; +} + +.source-icon.prettyPrint { + mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat; + mask-size: 100%; + background: var(--theme-highlight-blue); + fill: var(--theme-textbox-box-shadow); +} + +.source-icon.blackBox { + mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat; + mask-size: 100%; + background: var(--theme-highlight-blue); +} + +.source-icon.react { + mask-size: 100%; + background: var(--theme-highlight-bluegrey); +} /* 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 . */ @@ -2902,37 +2933,6 @@ debug-expression-error { border-radius: 2px; margin: 0 -1px -1px -1px; } -.source-icon { - position: relative; - background-color: var(--theme-comment); - mask-size: 100%; - display: inline-block; - margin-inline-end: 5px; -} - -.source-icon, -.source-icon svg { - width: 15px; - height: 15px; -} - -.source-icon.prettyPrint { - mask: url("chrome://devtools/skin/images/debugger/prettyPrint.svg") no-repeat; - mask-size: 100%; - background: var(--theme-highlight-blue); - fill: var(--theme-textbox-box-shadow); -} - -.source-icon.blackBox { - mask: url("chrome://devtools/skin/images/debugger/blackBox.svg") no-repeat; - mask-size: 100%; - background: var(--theme-highlight-blue); -} - -.source-icon.react { - mask-size: 100%; - background: var(--theme-highlight-bluegrey); -} /* 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 . */ diff --git a/devtools/client/debugger/new/src/components/Editor/index.js b/devtools/client/debugger/new/src/components/Editor/index.js index a37c795a8fd7..4ff680a9ef92 100644 --- a/devtools/client/debugger/new/src/components/Editor/index.js +++ b/devtools/client/debugger/new/src/components/Editor/index.js @@ -239,7 +239,7 @@ class Editor extends _react.PureComponent { } setupEditor() { - const editor = (0, _editor.createEditor)(); // disables the default search shortcuts + const editor = (0, _editor.getEditor)(); // disables the default search shortcuts // $FlowIgnore editor._initShortcuts = () => {}; @@ -284,7 +284,6 @@ class Editor extends _react.PureComponent { this.setState({ editor }); - (0, _editor.setEditor)(editor); return editor; } diff --git a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js index f7ef4a606bb0..9e5540acc8f7 100644 --- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js +++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js @@ -16,6 +16,10 @@ var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors"). var _reactRedux = require("devtools/client/shared/vendor/react-redux"); +var _SourceIcon = require("../shared/SourceIcon"); + +var _SourceIcon2 = _interopRequireDefault(_SourceIcon); + var _selectors = require("../../selectors/index"); var _sourceTree = require("../../actions/source-tree"); @@ -311,8 +315,8 @@ var _initialiseProps = function () { } const source = this.getSource(item); - return _react2.default.createElement("img", { - className: (0, _classnames2.default)((0, _source.getSourceClassnames)(source), "source-icon") + return _react2.default.createElement(_SourceIcon2.default, { + source: source }); }; diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js index db64e290beff..e8f4f9124d88 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js @@ -138,16 +138,16 @@ class Breakpoint extends _react.PureComponent { highlightText() { const text = this.getBreakpointText(); - const codeMirror = (0, _editor.getCodeMirror)(); + const editor = (0, _editor.getEditor)(); - if (!text || !codeMirror) { + if (!editor.CodeMirror) { return { - __html: "" + __html: text }; } const node = document.createElement("div"); - codeMirror.constructor.runMode(text, "application/javascript", node); + editor.CodeMirror.runMode(text, "application/javascript", node); return { __html: node.innerHTML }; diff --git a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js index 3a4019fd3d23..d04951a707dd 100644 --- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js +++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js @@ -81,7 +81,8 @@ class Breakpoints extends _react.Component { key: source.url, onClick: () => this.props.selectSource(source.id) }, _react2.default.createElement(_SourceIcon2.default, { - source: source + source: source, + shouldHide: icon => ["file", "javascript"].includes(icon) }), (0, _source.getFilename)(source)), ...breakpoints.map(breakpoint => _react2.default.createElement(_Breakpoint2.default, { breakpoint: breakpoint, source: source, diff --git a/devtools/client/debugger/new/src/utils/editor/index.js b/devtools/client/debugger/new/src/utils/editor/index.js index c0faf5e5f5c3..f56f27ec4237 100644 --- a/devtools/client/debugger/new/src/utils/editor/index.js +++ b/devtools/client/debugger/new/src/utils/editor/index.js @@ -51,21 +51,7 @@ Object.keys(_ui).forEach(function (key) { } }); }); - -var _createEditor = require("./create-editor"); - -Object.keys(_createEditor).forEach(function (key) { - if (key === "default" || key === "__esModule") return; - Object.defineProperty(exports, key, { - enumerable: true, - get: function () { - return _createEditor[key]; - } - }); -}); -exports.setEditor = setEditor; exports.getEditor = getEditor; -exports.getCodeMirror = getCodeMirror; exports.removeEditor = removeEditor; exports.shouldShowPrettyPrint = shouldShowPrettyPrint; exports.shouldShowFooter = shouldShowFooter; @@ -84,6 +70,8 @@ exports.clearLineClass = clearLineClass; exports.getTextForLine = getTextForLine; exports.getCursorLine = getCursorLine; +var _createEditor = require("./create-editor"); + var _source = require("../source"); var _wasm = require("../wasm"); @@ -96,16 +84,13 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope let editor; -function setEditor(_editor) { - editor = _editor; -} - function getEditor() { - return editor; -} + if (editor) { + return editor; + } -function getCodeMirror() { - return editor && editor.codeMirror; + editor = (0, _createEditor.createEditor)(); + return editor; } function removeEditor() { diff --git a/devtools/client/debugger/new/src/utils/editor/source-editor.js b/devtools/client/debugger/new/src/utils/editor/source-editor.js index 4dcd04a5aa90..00b1cf010fa8 100644 --- a/devtools/client/debugger/new/src/utils/editor/source-editor.js +++ b/devtools/client/debugger/new/src/utils/editor/source-editor.js @@ -75,6 +75,10 @@ class SourceEditor { return this.editor; } + get CodeMirror() { + return CodeMirror; + } + setText(str) { this.editor.setValue(str); } diff --git a/devtools/client/sourceeditor/editor.js b/devtools/client/sourceeditor/editor.js index a9e5fad2834f..a83ba0f82570 100644 --- a/devtools/client/sourceeditor/editor.js +++ b/devtools/client/sourceeditor/editor.js @@ -217,6 +217,15 @@ Editor.prototype = { config: null, Doc: null, + /** + * Exposes the CodeMirror class. We want to be able to + * invoke static commands such as runMode for syntax highlighting. + */ + get CodeMirror() { + const codeMirror = editors.get(this); + return codeMirror && codeMirror.constructor; + }, + /** * Exposes the CodeMirror instance. We want to get away from trying to * abstract away the API entirely, and this makes it easier to integrate in From c5dba70b0bad610d9ee6396851f475d082cc0097 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 1 Jun 2018 17:55:58 +0200 Subject: [PATCH 037/116] Bug 1422365 - Introduce nsIClearDataService - part 20 - disable android xpcshell, r=me CLOSED TREE --- toolkit/components/cleardata/tests/unit/xpcshell.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.ini b/toolkit/components/cleardata/tests/unit/xpcshell.ini index 9bdae7c8f86f..bc779512311a 100644 --- a/toolkit/components/cleardata/tests/unit/xpcshell.ini +++ b/toolkit/components/cleardata/tests/unit/xpcshell.ini @@ -1,5 +1,6 @@ [DEFAULT] head = head.js +skip-if = toolkit == 'android' support-files = [test_basic.js] From 2c5b7db57075b79f25f35621cf546c56b403a8aa Mon Sep 17 00:00:00 2001 From: Brindusan Cristian Date: Fri, 1 Jun 2018 19:07:24 +0300 Subject: [PATCH 038/116] Backed out changeset f8dbb1d2d07c (bug 1464400) for mochitest failures on test_font_whitelist.html. CLOSED TREE --- dom/chrome-webidl/InspectorUtils.webidl | 2 - gfx/thebes/gfxDWriteFontList.cpp | 4 +- gfx/thebes/gfxDWriteFontList.h | 2 +- gfx/thebes/gfxFcPlatformFontList.cpp | 17 +++-- gfx/thebes/gfxFcPlatformFontList.h | 6 +- gfx/thebes/gfxFont.h | 13 ++-- gfx/thebes/gfxFontEntry.h | 25 -------- gfx/thebes/gfxFontFamilyList.h | 2 +- gfx/thebes/gfxGDIFontList.cpp | 4 +- gfx/thebes/gfxGDIFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.mm | 2 +- gfx/thebes/gfxPlatformFontList.cpp | 19 +++--- gfx/thebes/gfxPlatformFontList.h | 13 ++-- gfx/thebes/gfxTextRun.cpp | 57 ++++++----------- gfx/thebes/gfxTextRun.h | 28 +++------ layout/inspector/InspectorFontFace.cpp | 14 ----- layout/inspector/InspectorFontFace.h | 1 - layout/inspector/tests/chrome/chrome.ini | 1 - .../tests/chrome/test_fontFaceGeneric.xul | 62 ------------------- layout/style/ServoBindings.h | 2 +- 21 files changed, 64 insertions(+), 214 deletions(-) delete mode 100644 layout/inspector/tests/chrome/test_fontFaceGeneric.xul diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index 0ab6a0ba6ea3..1591f92a801b 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -135,8 +135,6 @@ interface InspectorFontFace { readonly attribute DOMString CSSFamilyName; // a family name that could be used in CSS font-family // (not necessarily the actual name that was used, // due to aliases, generics, localized names, etc) - readonly attribute DOMString CSSGeneric; // CSS generic (serif, sans-serif, etc) that was mapped - // to this font, if any (frequently empty!) [NewObject,Throws] sequence getVariationAxes(); [NewObject,Throws] sequence getVariationInstances(); diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index e29f030f5be8..06133658c765 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1426,7 +1426,7 @@ gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName, bool gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1436,7 +1436,7 @@ gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(FamilyAndGeneric(ff)); + aOutput->AppendElement(ff); return true; } diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 426c72cb5b1c..37b62db94ca7 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -427,7 +427,7 @@ public: bool UseGDIFontTableAccess() { return mGDIFontTableAccess; } bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 5c0cd8f092b1..987b08d19c88 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -1893,7 +1893,7 @@ gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName, bool gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1941,7 +1941,7 @@ gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, // Because the FcConfigSubstitute call is quite expensive, we cache the // actual font families found via this process. So check the cache first: NS_ConvertUTF16toUTF8 familyToFind(familyName); - AutoTArray cachedFamilies; + AutoTArray cachedFamilies; if (mFcSubstituteCache.Get(familyToFind, &cachedFamilies)) { if (cachedFamilies.IsEmpty()) { return false; @@ -2090,7 +2090,7 @@ gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, void gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { bool usePrefFontList = false; @@ -2147,10 +2147,7 @@ gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, PrefFontList* prefFonts = FindGenericFamilies(genericToLookup, aLanguage); NS_ASSERTION(prefFonts, "null generic font list"); - aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); - for (auto& f : *prefFonts) { - aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); - } + aFamilyList.AppendElements(*prefFonts); } void @@ -2261,14 +2258,14 @@ gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric, FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric); if (mappedGeneric) { NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric)); - AutoTArray genericFamilies; + AutoTArray genericFamilies; if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName, &genericFamilies, FindFamiliesFlags(0))) { MOZ_ASSERT(genericFamilies.Length() == 1, "expected a single family"); - if (!prefFonts->Contains(genericFamilies[0].mFamily)) { - prefFonts->AppendElement(genericFamilies[0].mFamily); + if (!prefFonts->Contains(genericFamilies[0])) { + prefFonts->AppendElement(genericFamilies[0]); bool foundLang = !fcLang.IsEmpty() && PatternHasLang(font, ToFcChar8Ptr(fcLang.get())); diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 63950d5e5ef1..251990035dcd 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -305,7 +305,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; @@ -318,7 +318,7 @@ public: // override to use fontconfig lookup for generics void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) override; + nsTArray& aFamilyList) override; void ClearLangGroupPrefFonts() override; @@ -399,7 +399,7 @@ protected: // these pointers will be invalidated. InitFontList() flushes the cache // in this case. nsDataHashtable> mFcSubstituteCache; + nsTArray> mFcSubstituteCache; nsCOMPtr mCheckFontUpdatesTimer; nsCountedRef mLastConfig; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 8eb7d160c91e..e122e90d23c2 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -631,17 +631,12 @@ protected: }; struct gfxTextRange { - enum class MatchType : uint16_t { - // The CSS generic that mapped to this font, if any. This field of - // the MatchType stores a FontFamilyType value as defined in the enum - // in gfxFontFamilyList.h. - kGenericMask = 0x00ff, - + enum class MatchType : uint8_t { // Flags for recording the kind of font-matching that was used. // Note that multiple flags may be set on a single range. - kFontGroup = 0x0100, - kPrefsFallback = 0x0200, - kSystemFallback = 0x0400 + kFontGroup = 0x01, + kPrefsFallback = 0x02, + kSystemFallback = 0x04 }; gfxTextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont, MatchType aMatchType, diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index 8e975a2bc7cf..c1246ed90240 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -925,29 +925,4 @@ protected: }; }; -// Struct used in the gfxFontGroup font list to keep track of a font family -// together with the CSS generic (if any) that was mapped to it in this -// particular case (so it can be reported to the DevTools font inspector). -struct FamilyAndGeneric final { - FamilyAndGeneric() - : mFamily(nullptr) - , mGeneric(mozilla::FontFamilyType::eFamily_none) - { - } - FamilyAndGeneric(const FamilyAndGeneric& aOther) - : mFamily(aOther.mFamily) - , mGeneric(aOther.mGeneric) - { - } - explicit FamilyAndGeneric(gfxFontFamily* aFamily, - mozilla::FontFamilyType aGeneric = - mozilla::FontFamilyType::eFamily_none) - : mFamily(aFamily) - , mGeneric(aGeneric) - { - } - gfxFontFamily* mFamily; - mozilla::FontFamilyType mGeneric; -}; - #endif diff --git a/gfx/thebes/gfxFontFamilyList.h b/gfx/thebes/gfxFontFamilyList.h index e60e789f7903..ccfd3476edf9 100644 --- a/gfx/thebes/gfxFontFamilyList.h +++ b/gfx/thebes/gfxFontFamilyList.h @@ -23,7 +23,7 @@ namespace mozilla { * between unquoted and quoted names for serializaiton */ -enum FontFamilyType : uint8_t { +enum FontFamilyType : uint32_t { eFamily_none = 0, // used when finding generics // explicitly named font family (e.g. Helvetica) diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 1b83d7f74dfb..aff93de8aac0 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -882,7 +882,7 @@ gfxGDIFontList::MakePlatformFont(const nsAString& aFontName, bool gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -892,7 +892,7 @@ gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(FamilyAndGeneric(ff)); + aOutput->AppendElement(ff); return true; } diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 8530497dd19c..8d18a0c9d125 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -326,7 +326,7 @@ public: gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 281341bfdc5a..ee220b8a80ab 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -156,7 +156,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index f7435257f377..f42239e4b854 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -1628,7 +1628,7 @@ static const char kSystemFont_system[] = "-apple-system"; bool gfxMacPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index aebf33faeef8..faa30e86c11b 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -751,7 +751,7 @@ gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily) bool gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -818,7 +818,7 @@ gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, } if (familyEntry) { - aOutput->AppendElement(FamilyAndGeneric(familyEntry)); + aOutput->AppendElement(familyEntry); return true; } @@ -1011,12 +1011,12 @@ gfxPlatformFontList::GetFontFamiliesFromGenericFamilies( gfxFontStyle style; style.language = aLangGroup; style.systemFont = false; - AutoTArray families; + AutoTArray families; FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0), &style); - for (const FamilyAndGeneric& f : families) { - if (!aGenericFamilies->Contains(f.mFamily)) { - aGenericFamilies->AppendElement(f.mFamily); + for (gfxFontFamily* f : families) { + if (!aGenericFamilies->Contains(f)) { + aGenericFamilies->AppendElement(f); } } } @@ -1055,7 +1055,7 @@ gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, void gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // map lang ==> langGroup nsAtom* langGroup = GetLangGroup(aLanguage); @@ -1068,10 +1068,7 @@ gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, GetPrefFontsLangGroup(aGenericType, prefLang); if (!prefFonts->IsEmpty()) { - aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); - for (auto& f : *prefFonts) { - aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); - } + aFamilyList.AppendElements(*prefFonts); } } diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 3b89bd94d84d..34f427a75817 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -166,7 +166,7 @@ public: // Return true if any match was found and appended, false if none. virtual bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); @@ -263,7 +263,7 @@ public: virtual void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList); + nsTArray& aFamilyList); nsTArray>* GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, @@ -305,8 +305,6 @@ public: bool AddWithLegacyFamilyName(const nsAString& aLegacyName, gfxFontEntry* aFontEntry); - static const char* GetGenericName(mozilla::FontFamilyType aGenericType); - protected: class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable { @@ -405,13 +403,12 @@ protected: gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { - AutoTArray families; + AutoTArray families; return FindAndAddFamilies(aFamily, &families, aFlags, aStyle, - aDevToCssSize) - ? families[0].mFamily : nullptr; + aDevToCssSize) ? families[0] : nullptr; } // Lookup family name in global family list without substitutions or @@ -491,6 +488,8 @@ protected: // helper function to map lang to lang group nsAtom* GetLangGroup(nsAtom* aLanguage); + static const char* GetGenericName(mozilla::FontFamilyType aGenericType); + // gfxFontInfoLoader overrides, used to load in font cmaps virtual void InitLoader() override; virtual bool LoadFontInfo() override; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index f00f9ace5afa..67982992e82f 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1796,7 +1796,7 @@ void gfxFontGroup::BuildFontList() { // initialize fonts in the font family list - AutoTArray fonts; + AutoTArray fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); // lookup fonts in the fontlist @@ -1822,14 +1822,14 @@ gfxFontGroup::BuildFontList() } // build the fontlist from the specified families - for (const auto& f : fonts) { - AddFamilyToFontList(f.mFamily, f.mGeneric); + for (gfxFontFamily* fontFamily : fonts) { + AddFamilyToFontList(fontFamily); } } void gfxFontGroup::AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // First, look up in the user font set... // If the fontSet matches the family, we must not look for a platform @@ -1853,8 +1853,7 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, } void -gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, - FontFamilyType aGeneric) +gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) { NS_ASSERTION(aFamily, "trying to add a null font family to fontlist"); AutoTArray fontEntryList; @@ -1862,7 +1861,7 @@ gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, // add these to the fontlist for (gfxFontEntry* fe : fontEntryList) { if (!HasFont(fe)) { - FamilyFace ff(aFamily, fe, aGeneric); + FamilyFace ff(aFamily, fe); if (fe->mIsUserFontContainer) { ff.CheckState(mSkipDrawing); } @@ -2065,7 +2064,7 @@ gfxFontGroup::GetDefaultFont() } gfxFont* -gfxFontGroup::GetFirstValidFont(uint32_t aCh, FontFamilyType* aGeneric) +gfxFontGroup::GetFirstValidFont(uint32_t aCh) { uint32_t count = mFonts.Length(); for (uint32_t i = 0; i < count; ++i) { @@ -2077,9 +2076,6 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh, FontFamilyType* aGeneric) // already have a font? gfxFont* font = ff.Font(); if (font) { - if (aGeneric) { - *aGeneric = ff.Generic(); - } return font; } @@ -2103,15 +2099,9 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh, FontFamilyType* aGeneric) font = GetFontAt(i, aCh); if (font) { - if (aGeneric) { - *aGeneric = mFonts[i].Generic(); - } return font; } } - if (aGeneric) { - *aGeneric = eFamily_none; - } return GetDefaultFont(); } @@ -2899,8 +2889,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* firstFont = GetFontAt(0, aCh); if (firstFont) { if (firstFont->HasCharacter(aCh)) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(mFonts[0].Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return firstFont; } @@ -2915,8 +2904,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, font = FindFallbackFaceForChar(mFonts[0].Family(), aCh); } if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(mFonts[0].Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return font; } } @@ -2966,8 +2954,6 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* font = ff.Font(); if (font) { if (font->HasCharacter(aCh)) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(ff.Generic()); return font; } continue; @@ -2996,8 +2982,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (pfe && pfe->HasCharacter(aCh)) { font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(mFonts[i].Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return font; } } @@ -3006,8 +2991,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, // build the font via GetFontAt font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(mFonts[i].Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return font; } } @@ -3020,8 +3004,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, "should only do fallback once per font family"); font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(ff.Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return font; } } else { @@ -3032,8 +3015,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (!fe->mIsUserFontContainer && !fe->IsUserFont()) { font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(ff.Generic()); + *aMatchType = gfxTextRange::MatchType::kFontGroup; return font; } } @@ -3102,13 +3084,11 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, // initialize prevFont to the group's primary font, so that this will be // used for string-initial control chars, etc rather than risk hitting font // fallback for these (bug 716229) - FontFamilyType generic = eFamily_none; - gfxFont *prevFont = GetFirstValidFont(' ', &generic); + gfxFont *prevFont = GetFirstValidFont(); // if we use the initial value of prevFont, we treat this as a match from // the font group; fixes bug 978313 - gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(generic); + gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup; for (uint32_t i = 0; i < aLength; i++) { @@ -3158,8 +3138,7 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, && !gfxFontUtils::IsJoinControl(ch) && !gfxFontUtils::IsJoinCauser(prevCh) && !gfxFontUtils::IsVarSelector(ch)))) { - matchType = gfxTextRange::MatchType::kFontGroup | - gfxTextRange::MatchType(mFonts[0].Generic()); + matchType = gfxTextRange::MatchType::kFontGroup; } else { font = FindFontForChar(ch, prevCh, nextCh, aRunScript, prevFont, &matchType); @@ -3167,9 +3146,9 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, #ifndef RELEASE_OR_BETA if (MOZ_UNLIKELY(mTextPerf)) { - if (matchType & gfxTextRange::MatchType::kPrefsFallback) { + if (matchType == gfxTextRange::MatchType::kPrefsFallback) { mTextPerf->current.fallbackPrefs++; - } else if (matchType & gfxTextRange::MatchType::kSystemFallback) { + } else if (matchType == gfxTextRange::MatchType::kSystemFallback) { mTextPerf->current.fallbackSystem++; } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index ed2e1a0c93fb..b55d25676373 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -864,11 +864,8 @@ public: virtual ~gfxFontGroup(); // Returns first valid font in the fontlist or default font. - // Initiates userfont loads if userfont not loaded. - // aGeneric: if non-null, returns the CSS generic type that was mapped to - // this font - gfxFont* GetFirstValidFont(uint32_t aCh = 0x20, - mozilla::FontFamilyType* aGeneric = nullptr); + // Initiates userfont loads if userfont not loaded + gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); // Returns the first font in the font-group that has an OpenType MATH table, // or null if no such font is available. The GetMathConstant methods may be @@ -1028,15 +1025,13 @@ protected: class FamilyFace { public: FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), - mGeneric(mozilla::eFamily_none), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { } - FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont, - mozilla::FontFamilyType aGeneric) - : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(true), + FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) + : mFamily(aFamily), mFontCreated(true), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFont, "font pointer must not be null"); @@ -1047,9 +1042,8 @@ protected: NS_ADDREF(aFont); } - FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, - mozilla::FontFamilyType aGeneric) - : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(false), + FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry) + : mFamily(aFamily), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); @@ -1062,7 +1056,6 @@ protected: FamilyFace(const FamilyFace& aOtherFamilyFace) : mFamily(aOtherFamilyFace.mFamily), - mGeneric(aOtherFamilyFace.mGeneric), mFontCreated(aOtherFamilyFace.mFontCreated), mLoading(aOtherFamilyFace.mLoading), mInvalid(aOtherFamilyFace.mInvalid), @@ -1095,7 +1088,6 @@ protected: } mFamily = aOther.mFamily; - mGeneric = aOther.mGeneric; mFontCreated = aOther.mFontCreated; mLoading = aOther.mLoading; mInvalid = aOther.mInvalid; @@ -1120,8 +1112,6 @@ protected: return mFontCreated ? mFont->GetFontEntry() : mFontEntry; } - mozilla::FontFamilyType Generic() const { return mGeneric; } - bool IsUserFontContainer() const { return FontEntry()->mIsUserFontContainer; } @@ -1158,7 +1148,6 @@ protected: gfxFont* MOZ_OWNING_REF mFont; gfxFontEntry* MOZ_OWNING_REF mFontEntry; }; - mozilla::FontFamilyType mGeneric; bool mFontCreated : 1; bool mLoading : 1; bool mInvalid : 1; @@ -1270,11 +1259,10 @@ protected: // lookup and add a font with a given name (i.e. *not* a generic!) void AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList); + nsTArray& aFamilyList); // do style selection and add entries to list - void AddFamilyToFontList(gfxFontFamily* aFamily, - mozilla::FontFamilyType aGeneric); + void AddFamilyToFontList(gfxFontFamily* aFamily); }; // A "missing font recorder" is to be used during text-run creation to keep diff --git a/layout/inspector/InspectorFontFace.cpp b/layout/inspector/InspectorFontFace.cpp index 1d28177ebb70..ea099428f8e9 100644 --- a/layout/inspector/InspectorFontFace.cpp +++ b/layout/inspector/InspectorFontFace.cpp @@ -6,7 +6,6 @@ #include "InspectorFontFace.h" -#include "gfxPlatformFontList.h" #include "gfxTextRun.h" #include "gfxUserFontSet.h" #include "nsFontFaceLoader.h" @@ -56,19 +55,6 @@ InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) aCSSFamilyName = mFontEntry->FamilyName(); } -void -InspectorFontFace::GetCSSGeneric(nsAString& aName) -{ - auto genericType = - FontFamilyType(mMatchType & gfxTextRange::MatchType::kGenericMask); - if (genericType >= FontFamilyType::eFamily_generic_first && - genericType <= FontFamilyType::eFamily_generic_last) { - aName.AssignASCII(gfxPlatformFontList::GetGenericName(genericType)); - } else { - aName.Truncate(0); - } -} - ServoFontFaceRule* InspectorFontFace::GetRule() { diff --git a/layout/inspector/InspectorFontFace.h b/layout/inspector/InspectorFontFace.h index a123bbcbb9de..501cf6bb86f2 100644 --- a/layout/inspector/InspectorFontFace.h +++ b/layout/inspector/InspectorFontFace.h @@ -56,7 +56,6 @@ public: bool FromSystemFallback(); void GetName(nsAString& aName); void GetCSSFamilyName(nsAString& aCSSFamilyName); - void GetCSSGeneric(nsAString& aGeneric); ServoFontFaceRule* GetRule(); int32_t SrcIndex(); void GetURI(nsAString& aURI); diff --git a/layout/inspector/tests/chrome/chrome.ini b/layout/inspector/tests/chrome/chrome.ini index a8866410d9ba..3d7fc5affcf7 100644 --- a/layout/inspector/tests/chrome/chrome.ini +++ b/layout/inspector/tests/chrome/chrome.ini @@ -28,4 +28,3 @@ support-files = skip-if = (os == 'win' || os == 'linux' || os == 'mac') # bug 1433438, bug 1456855, bug 1456856 support-files = test_fontVariationsAPI.css -[test_fontFaceGeneric.xul] diff --git a/layout/inspector/tests/chrome/test_fontFaceGeneric.xul b/layout/inspector/tests/chrome/test_fontFaceGeneric.xul deleted file mode 100644 index 6c97f7f28c76..000000000000 --- a/layout/inspector/tests/chrome/test_fontFaceGeneric.xul +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - -
test one
-
test two
-
test three
- - -
diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index 6179fbe40424..193f2c1d5961 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -36,7 +36,7 @@ struct nsFont; namespace mozilla { class FontFamilyList; struct FontFamilyName; - enum FontFamilyType : uint8_t; + enum FontFamilyType : uint32_t; class SharedFontList; enum class CSSPseudoElementType : uint8_t; struct Keyframe; From a8662a7938294485e93b681ed576df282c3ee0dc Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 29 May 2018 17:18:39 +0200 Subject: [PATCH 039/116] Bug 1456265 - Make ChannelSplitterNode have a channelCountMode of "explicit" and a channelIntepretation of "discrete" by default. r=achronop MozReview-Commit-ID: 5pAdWn9zV9e --HG-- extra : rebase_source : bcb5fcac629a403a12481b55e577facf57c2fca5 extra : intermediate-source : ebfc3c04016ab0cce5489973e63cdb6dfdee191c extra : source : 42f845da213bcb73fb3400d6628e3ffc15b3992b --- dom/media/webaudio/ChannelSplitterNode.cpp | 6 +++--- dom/media/webaudio/test/test_channelSplitterNode.html | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/media/webaudio/ChannelSplitterNode.cpp b/dom/media/webaudio/ChannelSplitterNode.cpp index 23c714a5bf4a..4baf001ff153 100644 --- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -53,9 +53,9 @@ public: ChannelSplitterNode::ChannelSplitterNode(AudioContext* aContext, uint16_t aOutputCount) : AudioNode(aContext, - 2, - ChannelCountMode::Max, - ChannelInterpretation::Speakers) + 6, + ChannelCountMode::Explicit, + ChannelInterpretation::Discrete) , mOutputCount(aOutputCount) { mStream = AudioNodeStream::Create(aContext, diff --git a/dom/media/webaudio/test/test_channelSplitterNode.html b/dom/media/webaudio/test/test_channelSplitterNode.html index bfe29b60d07a..65cea70d6cdc 100644 --- a/dom/media/webaudio/test/test_channelSplitterNode.html +++ b/dom/media/webaudio/test/test_channelSplitterNode.html @@ -30,9 +30,9 @@ addLoadEvent(function() { var source = context.createBufferSource(); var splitter = new ChannelSplitterNode(context); - is(splitter.channelCount, 2, "splitter node has 2 input channels by default"); - is(splitter.channelCountMode, "max", "Correct channelCountMode for the splitter node"); - is(splitter.channelInterpretation, "speakers", "Correct channelCountInterpretation for the splitter node"); + is(splitter.channelCount, 6, "splitter node has 2 input channels by default"); + is(splitter.channelCountMode, "explicit", "Correct channelCountMode for the splitter node"); + is(splitter.channelInterpretation, "discrete", "Correct channelCountInterpretation for the splitter node"); source.buffer = buffer; source.connect(splitter); From 54199c6959cf7095247d24fe9d389fb7ba2b653a Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 29 May 2018 18:15:29 +0200 Subject: [PATCH 040/116] Bug 1456946 - Don't call AudioNode::Initialize on an ChannelSplitterNode during construction to avoid throwing. r=achronop We initialize the channelCountMode and channelInterpretation (that cannot be changed) appropriately in the C++ ctor, and the channelCount manually as well. Then we check manually that the options for the channelCountMode, the channelCount and channelInterpretation have not been passed, or are not incorrect. MozReview-Commit-ID: 4YdYfaGqKqn --HG-- extra : rebase_source : 54000c4f79361945142bb413b7eeebb2967d4fbb extra : intermediate-source : 9a085b0513f78344b07724c049860b089c313894 extra : source : 852233de6408712da07a2f09721c7e35d67d608f --- dom/media/webaudio/ChannelSplitterNode.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dom/media/webaudio/ChannelSplitterNode.cpp b/dom/media/webaudio/ChannelSplitterNode.cpp index 4baf001ff153..7ac16e50100c 100644 --- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -82,8 +82,22 @@ ChannelSplitterNode::Create(AudioContext& aAudioContext, RefPtr audioNode = new ChannelSplitterNode(&aAudioContext, aOptions.mNumberOfOutputs); - audioNode->Initialize(aOptions, aRv); - if (NS_WARN_IF(aRv.Failed())) { + // Manually check that the other options are valid, this node has channelCount, + // channelCountMode and channelInterpretation constraints: they cannot be + // changed from the default. + if (aOptions.mChannelCount.WasPassed() && + aOptions.mChannelCount.Value() != audioNode->ChannelCount()) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + if (aOptions.mChannelInterpretation.WasPassed() && + aOptions.mChannelInterpretation.Value() != audioNode->ChannelInterpretationValue()) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + if (aOptions.mChannelCountMode.WasPassed() && + aOptions.mChannelCountMode.Value() != audioNode->ChannelCountModeValue()) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } From f286db11ce17ea236242d607473929a435fef5c4 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Tue, 29 May 2018 18:16:24 +0200 Subject: [PATCH 041/116] Bug 1456946 - Properly reflect the channelCount when set in the ctor using the option object, on a ChannelSplitterNode. r=achronop MozReview-Commit-ID: DrnadeBS8hi --HG-- extra : rebase_source : ca28ff595fdefaf8327c0a6ef4826f3b2cd02368 extra : intermediate-source : 9af1ffb437be63b6956970b47eebc78e6e2310af extra : source : 91a4b9b7cfa8444e760a99ae4518e678e1cc14ef --- dom/media/webaudio/ChannelSplitterNode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/webaudio/ChannelSplitterNode.cpp b/dom/media/webaudio/ChannelSplitterNode.cpp index 7ac16e50100c..6aef8c2918a8 100644 --- a/dom/media/webaudio/ChannelSplitterNode.cpp +++ b/dom/media/webaudio/ChannelSplitterNode.cpp @@ -53,7 +53,7 @@ public: ChannelSplitterNode::ChannelSplitterNode(AudioContext* aContext, uint16_t aOutputCount) : AudioNode(aContext, - 6, + aOutputCount, ChannelCountMode::Explicit, ChannelInterpretation::Discrete) , mOutputCount(aOutputCount) From 9db578f6ea6a7f36c8b6ce63d6dbee78d87c4c4f Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Wed, 30 May 2018 14:01:34 +0200 Subject: [PATCH 042/116] Bug 1456265 - Update the WPT expectation file, the ChannelSplitterNode tests are now passing. --HG-- extra : rebase_source : 1d77fa135af7e913e3b31bd2d54ed38f21c23789 extra : intermediate-source : 2844a12783a039b6dc0c725830e66803c9bfdbb1 extra : source : be22684cddb8ecf3caebb1d77e0aae42a4859b92 --- .../ctor-channelsplitter.html.ini | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 testing/web-platform/meta/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html.ini diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html.ini deleted file mode 100644 index dd964d2e5ae3..000000000000 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-channelsplitternode-interface/ctor-channelsplitter.html.ini +++ /dev/null @@ -1,17 +0,0 @@ -[ctor-channelsplitter.html] - expected: ERROR - [X node0.channelCount is not equal to 6. Got 2.] - expected: FAIL - - [X node0.channelCountMode is not equal to explicit. Got max.] - expected: FAIL - - [X node0.channelInterpretation is not equal to discrete. Got speakers.] - expected: FAIL - - [< [default constructor\] 3 out of 7 assertions were failed.] - expected: FAIL - - [X new ChannelSplitterNode(c, {channelCount: 6}} incorrectly threw InvalidStateError: "An attempt was made to use an object that is not, or is no longer, usable".] - expected: FAIL - From b0d0866f95656e66890243e0eed508cb2c10c5aa Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Wed, 30 May 2018 18:23:37 +0200 Subject: [PATCH 043/116] Bug 1456265 - Also update test_channelSplitterNodeWithVolume.html --HG-- extra : rebase_source : 353b42cb78e73aa35caa4d6375f67f1769cf6add extra : intermediate-source : eb7cba7e1120302f696c002d42cae86d3de1d4b5 extra : source : ee0c4548a78a794de83ce82d994bd5cfa6c84e23 --- .../webaudio/test/test_channelSplitterNodeWithVolume.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dom/media/webaudio/test/test_channelSplitterNodeWithVolume.html b/dom/media/webaudio/test/test_channelSplitterNodeWithVolume.html index 8e16271f3679..f0451d9c67dc 100644 --- a/dom/media/webaudio/test/test_channelSplitterNodeWithVolume.html +++ b/dom/media/webaudio/test/test_channelSplitterNodeWithVolume.html @@ -32,9 +32,9 @@ addLoadEvent(function() { var source = context.createBufferSource(); var splitter = context.createChannelSplitter(); - is(splitter.channelCount, 2, "splitter node has 2 input channels by default"); - is(splitter.channelCountMode, "max", "Correct channelCountMode for the splitter node"); - is(splitter.channelInterpretation, "speakers", "Correct channelCountInterpretation for the splitter node"); + is(splitter.channelCount, 6, "splitter node has 2 input channels by default"); + is(splitter.channelCountMode, "explicit", "Correct channelCountMode for the splitter node"); + is(splitter.channelInterpretation, "discrete", "Correct channelCountInterpretation for the splitter node"); source.buffer = buffer; var gain = context.createGain(); From 92b876c41596fb17f6c927a97814d2071f8888bf Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Thu, 31 May 2018 14:00:32 +0200 Subject: [PATCH 044/116] Bug 1468822 - Update expectations for convolver-response-1-chan.html. --HG-- extra : rebase_source : 71eff8141d3bb31c6e31e56dadef3d5b63f39b2c extra : intermediate-source : d2de759839fa8a1c98a1787c0025ad4f67956714 extra : source : 7f0401a2f5dff47bc33e6d8952975738da8c818e --- .../convolver-response-1-chan.html.ini | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini b/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini index b16c9494baf0..cc756181c38d 100644 --- a/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini +++ b/testing/web-platform/meta/webaudio/the-audio-api/the-convolvernode-interface/convolver-response-1-chan.html.ini @@ -1,2 +1,73 @@ [convolver-response-1-chan.html] - expected: ERROR + [X 1: Channel 1: Expected 0 for all values but found 1280 unexpected values: \n\tIndex\tActual\n\t[0\]\t-1.4901161193847656e-7\n\t[1\]\t-8.940696716308594e-8\n\t[2\]\t0.3311062455177307\n\t[3\]\t0.6248594522476196\n\t...and 1276 more errors.] + expected: FAIL + + [< [1-channel input\] 1 out of 2 assertions were failed.] + expected: FAIL + + [X 2: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.4584089517593384e-1\n\t[3\]\t0.0000000000000000e+0\t8.4483337402343750e-1\n\t[4\]\t0.0000000000000000e+0\t8.2102525234222412e-1\n\t[5\]\t0.0000000000000000e+0\t8.6209857463836670e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 2: Channel 1 expected to be equal to the array [0,0,0.9918842315673828,0.7683960199356079,0.9083511829376221,0.7684863805770874,0.9814503192901611,0.3193226158618927,-0.9322392344474792,-0.8032255172729492,-0.8812425136566162,-0.7985008358955383,-0.9260328412055969,-0.600982666015625,0.7887306809425354,0.8655399680137634...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.9188423156738281e-1\n\t[3\]\t0.0000000000000000e+0\t7.6839601993560791e-1\n\t[4\]\t0.0000000000000000e+0\t9.0835118293762207e-1\n\t[5\]\t0.0000000000000000e+0\t7.6848638057708740e-1\n\t...and 1273 more errors.] + expected: FAIL + + [< [2-channel input\] 2 out of 2 assertions were failed.] + expected: FAIL + + [X 3: Channel 0 expected to be equal to the array [0,0,0.9458408951759338,0.8448333740234375,0.8210252523422241,0.8620985746383667,0.8430315852165222,0.855602502822876,0.7933436632156372,0.9865825176239014,0.3972480297088623,-0.7786127924919128,-0.9223549962043762,-0.7896472215652466,-0.8727429509162903,-0.8325281143188477...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.4584089517593384e-1\n\t[3\]\t0.0000000000000000e+0\t8.4483337402343750e-1\n\t[4\]\t0.0000000000000000e+0\t8.2102525234222412e-1\n\t[5\]\t0.0000000000000000e+0\t8.6209857463836670e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 3: Channel 1 expected to be equal to the array [0,0,0.9918842315673828,0.7683960199356079,0.9083511829376221,0.7684863805770874,0.9814503192901611,0.3193226158618927,-0.9322392344474792,-0.8032255172729492,-0.8812425136566162,-0.7985008358955383,-0.9260328412055969,-0.600982666015625,0.7887306809425354,0.8655399680137634...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.9188423156738281e-1\n\t[3\]\t0.0000000000000000e+0\t7.6839601993560791e-1\n\t[4\]\t0.0000000000000000e+0\t9.0835118293762207e-1\n\t[5\]\t0.0000000000000000e+0\t7.6848638057708740e-1\n\t...and 1273 more errors.] + expected: FAIL + + [< [3-channel input\] 2 out of 2 assertions were failed.] + expected: FAIL + + [X 4: Channel 0 expected to be equal to the array [0,0,0.9706697463989258,0.8062858581542969,0.8572278618812561,0.8353679776191711,0.1815471351146698,-0.06941461563110352,0.0376264750957489,-0.007540702819824219,-0.01803457736968994,0.029624849557876587,-0.021628618240356445,-0.005501270294189453,0.05631396174430847,-0.4426816999912262...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.7066974639892578e-1\n\t[3\]\t0.0000000000000000e+0\t8.0628585815429688e-1\n\t[4\]\t0.0000000000000000e+0\t8.5722786188125610e-1\n\t[5\]\t0.0000000000000000e+0\t8.3536797761917114e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 4: Channel 1 expected to be equal to the array [0,0,0.9692283868789673,0.8026213049888611,0.8825444579124451,0.18008126318454742,0.027644813060760498,-0.2844730615615845,-0.7766556739807129,-0.037477731704711914,-0.008235335350036621,0.07220342755317688,-0.3337171971797943,-0.7541778683662415,-0.020433425903320312,-0.0313774049282074...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.6922838687896729e-1\n\t[3\]\t0.0000000000000000e+0\t8.0262130498886108e-1\n\t[4\]\t0.0000000000000000e+0\t8.8254445791244507e-1\n\t[5\]\t0.0000000000000000e+0\t1.8008126318454742e-1\n\t...and 1273 more errors.] + expected: FAIL + + [< [4-channel input\] 2 out of 2 assertions were failed.] + expected: FAIL + + [X 5.1: Channel 0 expected to be equal to the array [0,0,2.2955899238586426,2.0720272064208984,1.532062292098999,0.8335829973220825,-0.21171289682388306,-0.005277678370475769,0.8338430523872375,1.0169568061828613,0.3252672553062439,-0.6764181852340698,-1.054646611213684,-0.5476447343826294,0.25095105171203613,-0.10892623662948608...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t2.2955899238586426e+0\n\t[3\]\t0.0000000000000000e+0\t2.0720272064208984e+0\n\t[4\]\t0.0000000000000000e+0\t1.5320622920989990e+0\n\t[5\]\t0.0000000000000000e+0\t8.3358299732208252e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 5.1: Channel 1 expected to be equal to the array [0,0,2.4002127647399902,1.8464014530181885,1.242234230041504,0.578858494758606,0.3615039587020874,0.16441935300827026,-0.7429117560386658,-1.5301964282989502,-1.898935079574585,-0.7277188301086426,0.01055973768234253,0.7105643153190613,1.7486152648925781,0.26711004972457886...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t2.4002127647399902e+0\n\t[3\]\t0.0000000000000000e+0\t1.8464014530181885e+0\n\t[4\]\t0.0000000000000000e+0\t1.2422342300415039e+0\n\t[5\]\t0.0000000000000000e+0\t5.7885849475860596e-1\n\t...and 1273 more errors.] + expected: FAIL + + [< [5.1-channel input\] 2 out of 2 assertions were failed.] + expected: FAIL + + [# AUDIT TASK RUNNER FINISHED: 5 out of 6 tasks were failed.] + expected: FAIL + + [X 1: Channel 1: Expected 0 for all values but found 1279 unexpected values: \n\tIndex\tActual\n\t[1\]\t-2.9802322387695312e-8\n\t[2\]\t0.33110618591308594\n\t[3\]\t0.6248594522476196\n\t[4\]\t0.8481202721595764\n\t...and 1275 more errors.] + expected: FAIL + + [X 2: Channel 0 expected to be equal to the array [0,0,0.9458407163619995,0.844833254814148,0.821025013923645,0.8620984554290771,0.8430314660072327,0.8556023836135864,0.7933435440063477,0.9865822792053223,0.39724797010421753,-0.7786126136779785,-0.9223548769950867,-0.7896471619606018,-0.8727428317070007,-0.8325279355049133...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.4584071636199951e-1\n\t[3\]\t0.0000000000000000e+0\t8.4483325481414795e-1\n\t[4\]\t0.0000000000000000e+0\t8.2102501392364502e-1\n\t[5\]\t0.0000000000000000e+0\t8.6209845542907715e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 2: Channel 1 expected to be equal to the array [0,0,0.9918840527534485,0.7683959007263184,0.9083510637283325,0.7684863805770874,0.9814502000808716,0.31932249665260315,-0.9322391152381897,-0.8032253384590149,-0.8812423348426819,-0.7985007762908936,-0.9260326027870178,-0.6009824872016907,0.7887305617332458,0.8655398488044739...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.9188405275344849e-1\n\t[3\]\t0.0000000000000000e+0\t7.6839590072631836e-1\n\t[4\]\t0.0000000000000000e+0\t9.0835106372833252e-1\n\t[5\]\t0.0000000000000000e+0\t7.6848638057708740e-1\n\t...and 1273 more errors.] + expected: FAIL + + [X 3: Channel 0 expected to be equal to the array [0,0,0.9458407163619995,0.844833254814148,0.821025013923645,0.8620984554290771,0.8430314660072327,0.8556023836135864,0.7933435440063477,0.9865822792053223,0.39724797010421753,-0.7786126136779785,-0.9223548769950867,-0.7896471619606018,-0.8727428317070007,-0.8325279355049133...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.4584071636199951e-1\n\t[3\]\t0.0000000000000000e+0\t8.4483325481414795e-1\n\t[4\]\t0.0000000000000000e+0\t8.2102501392364502e-1\n\t[5\]\t0.0000000000000000e+0\t8.6209845542907715e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 3: Channel 1 expected to be equal to the array [0,0,0.9918840527534485,0.7683959007263184,0.9083510637283325,0.7684863805770874,0.9814502000808716,0.31932249665260315,-0.9322391152381897,-0.8032253384590149,-0.8812423348426819,-0.7985007762908936,-0.9260326027870178,-0.6009824872016907,0.7887305617332458,0.8655398488044739...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.9188405275344849e-1\n\t[3\]\t0.0000000000000000e+0\t7.6839590072631836e-1\n\t[4\]\t0.0000000000000000e+0\t9.0835106372833252e-1\n\t[5\]\t0.0000000000000000e+0\t7.6848638057708740e-1\n\t...and 1273 more errors.] + expected: FAIL + + [X 4: Channel 0 expected to be equal to the array [0,0,0.9706696271896362,0.8062857389450073,0.8572276830673218,0.8353679180145264,0.1815471202135086,-0.06941458582878113,0.03762653470039368,-0.007540762424468994,-0.018034547567367554,0.029624909162521362,-0.021628588438034058,-0.0055013298988342285,0.05631396174430847,-0.44268161058425903...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.7066962718963623e-1\n\t[3\]\t0.0000000000000000e+0\t8.0628573894500732e-1\n\t[4\]\t0.0000000000000000e+0\t8.5722768306732178e-1\n\t[5\]\t0.0000000000000000e+0\t8.3536791801452637e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 4: Channel 1 expected to be equal to the array [0,0,0.9692282676696777,0.8026211857795715,0.8825443387031555,0.1800812929868698,0.027644872665405273,-0.28447312116622925,-0.7766556143760681,-0.037477701902389526,-0.008235275745391846,0.07220339775085449,-0.33371710777282715,-0.7541776895523071,-0.0204334557056427,-0.03137746453285217...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t9.6922826766967773e-1\n\t[3\]\t0.0000000000000000e+0\t8.0262118577957153e-1\n\t[4\]\t0.0000000000000000e+0\t8.8254433870315552e-1\n\t[5\]\t0.0000000000000000e+0\t1.8008129298686981e-1\n\t...and 1273 more errors.] + expected: FAIL + + [X 5.1: Channel 0 expected to be equal to the array [0,0,2.2955894470214844,2.0720269680023193,1.53206205368042,0.8335828185081482,-0.21171295642852783,-0.005277588963508606,0.8338429927825928,1.0169565677642822,0.3252672255039215,-0.6764179468154907,-1.0546464920043945,-0.5476447343826294,0.25095099210739136,-0.10892611742019653...\] but differs in 1276 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t2.2955894470214844e+0\n\t[3\]\t0.0000000000000000e+0\t2.0720269680023193e+0\n\t[4\]\t0.0000000000000000e+0\t1.5320620536804199e+0\n\t[5\]\t0.0000000000000000e+0\t8.3358281850814819e-1\n\t...and 1272 more errors.] + expected: FAIL + + [X 5.1: Channel 1 expected to be equal to the array [0,0,2.400212526321411,1.8464009761810303,1.2422339916229248,0.5788586139678955,0.3615038990974426,0.16441935300827026,-0.742911696434021,-1.530196189880371,-1.8989348411560059,-0.7277186512947083,0.010559797286987305,0.7105643153190613,1.748615026473999,0.26711004972457886...\] but differs in 1277 places:\n\tIndex\tActual\t\t\tExpected\n\t[2\]\t0.0000000000000000e+0\t2.4002125263214111e+0\n\t[3\]\t0.0000000000000000e+0\t1.8464009761810303e+0\n\t[4\]\t0.0000000000000000e+0\t1.2422339916229248e+0\n\t[5\]\t0.0000000000000000e+0\t5.7885861396789551e-1\n\t...and 1273 more errors.] + expected: FAIL + From 8e5587759f424118c4fb161e461160bb701a9acc Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Fri, 25 May 2018 17:35:43 -0400 Subject: [PATCH 045/116] Bug 1237182: Get rid of buildprops.json r=tomprince,sfraser Differential Revision: https://phabricator.services.mozilla.com/D1443 --HG-- extra : rebase_source : 1683b76377e27fdaa5292e1781573ddc4e61afa8 --- build/mozconfig.cache | 6 ------ python/mozbuild/mozbuild/artifacts.py | 3 +-- taskcluster/docker/android-build/Dockerfile | 6 ------ taskcluster/docker/debian7-build/Dockerfile | 6 ------ .../docker/desktop1604-test/buildprops.json | 8 -------- taskcluster/docker/mingw32-build/Dockerfile | 6 ------ .../scripts/periodic_file_updates.sh | 14 ++------------ taskcluster/docker/recipes/buildprops.json | 9 --------- .../releng_sub_windows_configs/32_add-on-devel.py | 1 - .../builds/releng_sub_windows_configs/32_debug.py | 1 - .../32_stat_and_debug.py | 1 - .../releng_sub_windows_configs/64_add-on-devel.py | 1 - .../builds/releng_sub_windows_configs/64_debug.py | 1 - testing/mozharness/external_tools/gittool.py | 1 - 14 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 taskcluster/docker/desktop1604-test/buildprops.json delete mode 100644 taskcluster/docker/recipes/buildprops.json diff --git a/build/mozconfig.cache b/build/mozconfig.cache index d9af826ec142..e2d072a375e4 100644 --- a/build/mozconfig.cache +++ b/build/mozconfig.cache @@ -7,12 +7,6 @@ # Avoid duplication if the file happens to be included twice. if test -z "$bucket" -a -z "$NO_CACHE"; then -# buildbot (or builders that use buildprops.json): -if [ -f $topsrcdir/../buildprops.json ]; then -read branch platform master < /dev/null) -EOF - bucket= if test -z "$SCCACHE_DISABLE"; then case "${branch}" in diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py index 60b9293486d2..c3e62d86767a 100644 --- a/python/mozbuild/mozbuild/artifacts.py +++ b/python/mozbuild/mozbuild/artifacts.py @@ -668,8 +668,7 @@ class TaskCache(CacheManager): for artifact_name in artifact_job.find_candidate_artifacts(artifacts): # We can easily extract the task ID from the URL. We can't easily # extract the build ID; we use the .ini files embedded in the - # downloaded artifact for this. We could also use the uploaded - # public/build/buildprops.json for this purpose. + # downloaded artifact for this. url = get_artifact_url(taskId, artifact_name) urls.append(url) if not urls: diff --git a/taskcluster/docker/android-build/Dockerfile b/taskcluster/docker/android-build/Dockerfile index 99f9121800e0..ac86a89c2eb3 100644 --- a/taskcluster/docker/android-build/Dockerfile +++ b/taskcluster/docker/android-build/Dockerfile @@ -48,12 +48,6 @@ COPY topsrcdir/taskcluster/docker/recipes/xvfb.sh /builds/worker/scripts/xvfb.sh # %include taskcluster/docker/recipes/oauth.txt COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ -# Add a stubbed out buildprops, which keeps mozharness from choking. -# Note that this needs to be in the parent of the workspace directory and in -# the directory where mozharness is run (not its --work-dir). -# %include taskcluster/docker/recipes/buildprops.json -COPY topsrcdir/taskcluster/docker/recipes/buildprops.json /builds/worker/ - # Reset user/workdir from parent image so we can install software. WORKDIR / USER root diff --git a/taskcluster/docker/debian7-build/Dockerfile b/taskcluster/docker/debian7-build/Dockerfile index c7243ae15d98..d725d3368a94 100644 --- a/taskcluster/docker/debian7-build/Dockerfile +++ b/taskcluster/docker/debian7-build/Dockerfile @@ -67,9 +67,3 @@ COPY topsrcdir/taskcluster/docker/recipes/xvfb.sh /builds/worker/scripts/xvfb.sh # mozharness is run (not its --work-dir). See Bug 1169652. # %include taskcluster/docker/recipes/oauth.txt COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ - -# stubbed out buildprops, which keeps mozharness from choking -# Note that this needs to be in the parent of the workspace directory and in -# the directory where mozharness is run (not its --work-dir) -# %include taskcluster/docker/recipes/buildprops.json -COPY topsrcdir/taskcluster/docker/recipes/buildprops.json /builds/worker/ diff --git a/taskcluster/docker/desktop1604-test/buildprops.json b/taskcluster/docker/desktop1604-test/buildprops.json deleted file mode 100644 index f0967b02625d..000000000000 --- a/taskcluster/docker/desktop1604-test/buildprops.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "properties": { - "buildername": "" - }, - "sourcestamp": { - "changes": [] - } -} diff --git a/taskcluster/docker/mingw32-build/Dockerfile b/taskcluster/docker/mingw32-build/Dockerfile index 0c9f7aa08ac6..c9956fe108dd 100644 --- a/taskcluster/docker/mingw32-build/Dockerfile +++ b/taskcluster/docker/mingw32-build/Dockerfile @@ -46,9 +46,3 @@ RUN apt-get update && \ # mozharness is run (not its --work-dir). See Bug 1169652. # %include taskcluster/docker/recipes/oauth.txt COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ - -# stubbed out buildprops, which keeps mozharness from choking -# Note that this needs to be in the parent of the workspace directory and in -# the directory where mozharness is run (not its --work-dir) -# %include taskcluster/docker/recipes/buildprops.json -COPY topsrcdir/taskcluster/docker/recipes/buildprops.json /builds/worker/ diff --git a/taskcluster/docker/periodic-updates/scripts/periodic_file_updates.sh b/taskcluster/docker/periodic-updates/scripts/periodic_file_updates.sh index 6668f86e25b8..5726fadaeaff 100755 --- a/taskcluster/docker/periodic-updates/scripts/periodic_file_updates.sh +++ b/taskcluster/docker/periodic-updates/scripts/periodic_file_updates.sh @@ -39,7 +39,6 @@ UNZIP="unzip -q" DIFF="$(which diff) -u" BASEDIR="${HOME}" TOOLSDIR="${HOME}/tools" -HGTOOL="${TOOLSDIR}/buildfarm/utils/hgtool.py" SCRIPTDIR="$(realpath "$(dirname "$0")")" HG="$(which hg)" @@ -351,20 +350,11 @@ function clone_build_tools { ${CLONE_CMD} } -# Clones an hg repo, using hgtool preferentially. +# Clones an hg repo function clone_repo { cd "${BASEDIR}" if [ ! -d "${REPODIR}" ]; then - CLONE_CMD="" - if [ -f "${HGTOOL}" ]; then - # Need to pass the default branch here to avoid pollution from buildprops.json - # when hgtool.py is run in production. - CLONE_CMD="${HGTOOL} --branch default" - else - echo "INFO: hgtool.py not found. Falling back to vanilla hg." - CLONE_CMD="${HG} clone" - fi - CLONE_CMD="${CLONE_CMD} ${HGREPO} ${REPODIR}" + CLONE_CMD="${HG} clone ${HGREPO} ${REPODIR}" ${CLONE_CMD} fi diff --git a/taskcluster/docker/recipes/buildprops.json b/taskcluster/docker/recipes/buildprops.json deleted file mode 100644 index f38b7d788e0b..000000000000 --- a/taskcluster/docker/recipes/buildprops.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "properties": { - "buildername": "" - }, - "sourcestamp": { - "changes": [] - }, - "comments": "TaskCluster Job" -} diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py index d8ea1696f4e3..c26ba825f8e5 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_add-on-devel.py @@ -16,7 +16,6 @@ config = { 'MOZ_OBJDIR': '%(abs_obj_dir)s', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' '%s' % (os.environ.get('path')), - 'PROPERTIES_FILE': os.path.join(os.getcwd(), 'buildprops.json'), 'TINDERBOX_OUTPUT': '1', 'XPCOM_DEBUG_BREAK': 'stack-and-abort', 'TOOLTOOL_CACHE': 'c:/builds/tooltool_cache', diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py index afa6002eae26..acca1bf6548f 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_debug.py @@ -17,7 +17,6 @@ config = { 'MOZ_OBJDIR': '%(abs_obj_dir)s', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' '%s' % (os.environ.get('path')), - 'PROPERTIES_FILE': os.path.join(os.getcwd(), 'buildprops.json'), 'TINDERBOX_OUTPUT': '1', 'XPCOM_DEBUG_BREAK': 'stack-and-abort', 'TOOLTOOL_CACHE': 'c:/builds/tooltool_cache', diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py index de0a24c40168..c560198ec056 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_stat_and_debug.py @@ -18,7 +18,6 @@ releng.manifest", 'MOZ_OBJDIR': '%(abs_obj_dir)s', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' '%s' % (os.environ.get('path')), - 'PROPERTIES_FILE': os.path.join(os.getcwd(), 'buildprops.json'), 'TINDERBOX_OUTPUT': '1', 'XPCOM_DEBUG_BREAK': 'stack-and-abort', 'TOOLTOOL_CACHE': 'c:/builds/tooltool_cache', diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py index 50edee48eca4..77cbd4f8312d 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_add-on-devel.py @@ -15,7 +15,6 @@ config = { 'MOZ_OBJDIR': '%(abs_obj_dir)s', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' '%s' % (os.environ.get('path')), - 'PROPERTIES_FILE': os.path.join(os.getcwd(), 'buildprops.json'), 'TINDERBOX_OUTPUT': '1', 'XPCOM_DEBUG_BREAK': 'stack-and-abort', 'TOOLTOOL_CACHE': 'c:/builds/tooltool_cache', diff --git a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py index 2adbd2d63d90..ed8b8f4b086f 100644 --- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_debug.py @@ -16,7 +16,6 @@ config = { 'MOZ_OBJDIR': '%(abs_obj_dir)s', 'PATH': 'C:/mozilla-build/nsis-3.01;C:/mozilla-build/python27;' '%s' % (os.environ.get('path')), - 'PROPERTIES_FILE': os.path.join(os.getcwd(), 'buildprops.json'), 'TINDERBOX_OUTPUT': '1', 'XPCOM_DEBUG_BREAK': 'stack-and-abort', 'TOOLTOOL_CACHE': 'c:/builds/tooltool_cache', diff --git a/testing/mozharness/external_tools/gittool.py b/testing/mozharness/external_tools/gittool.py index 520aeaf38eac..ee8ab272d0ce 100755 --- a/testing/mozharness/external_tools/gittool.py +++ b/testing/mozharness/external_tools/gittool.py @@ -42,7 +42,6 @@ if __name__ == '__main__': parser.set_defaults( revision=os.environ.get('GIT_REV'), branch=os.environ.get('GIT_BRANCH', None), - propsfile=os.environ.get('PROPERTIES_FILE'), loglevel=logging.INFO, shared_dir=os.environ.get('GIT_SHARE_BASE_DIR'), mirrors=None, From 600b5b46ac7c8783f4527b6bbd71e86fbf8ed40f Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Fri, 25 May 2018 17:43:15 -0400 Subject: [PATCH 046/116] Bug 1237182: get rid of oauth.txt r=mtabara Differential Revision: https://phabricator.services.mozilla.com/D1444 --HG-- extra : rebase_source : dad4f2102dc1e74b681a765169eae691724f8b61 --- build/mozconfig.cache | 37 +------------------ taskcluster/docker/android-build/Dockerfile | 7 ---- taskcluster/docker/debian7-build/Dockerfile | 7 ---- taskcluster/docker/mingw32-build/Dockerfile | 7 ---- taskcluster/docker/recipes/oauth.txt | 2 - .../mozharness/configs/awsy/linux_config.py | 1 - .../mozharness/configs/awsy/macosx_config.py | 1 - .../configs/marionette/prod_config.py | 3 -- .../configs/marionette/windows_config.py | 3 -- .../marionette/windows_taskcluster_config.py | 1 - .../raptor/linux64_config_taskcluster.py | 1 - .../mozharness/configs/raptor/linux_config.py | 1 - .../mozharness/configs/raptor/mac_config.py | 1 - .../configs/raptor/windows_config.py | 1 - .../configs/raptor/windows_vm_config.py | 1 - .../single_locale/ash_android-api-16.py | 1 - .../single_locale/autoland_android-api-16.py | 1 - .../single_locale/jamun_android-api-16.py | 1 - .../single_locale/maple_android-api-16.py | 1 - .../mozilla-aurora_android-api-16.py | 1 - .../mozilla-beta_android-api-16.py | 1 - .../mozilla-central_android-api-16.py | 1 - .../mozilla-inbound_android-api-16.py | 1 - .../mozilla-release_android-api-16.py | 1 - .../single_locale/try_android-api-16.py | 1 - .../talos/linux64_config_taskcluster.py | 1 - .../mozharness/configs/talos/linux_config.py | 1 - .../mozharness/configs/talos/mac_config.py | 1 - .../configs/talos/windows_config.py | 1 - .../talos/windows_taskcluster_config.py | 1 - .../configs/talos/windows_vm_config.py | 1 - .../configs/unittests/linux_unittest.py | 1 - .../configs/unittests/mac_unittest.py | 1 - .../unittests/win_taskcluster_unittest.py | 1 - .../configs/unittests/win_unittest.py | 1 - .../configs/web_platform_tests/prod_config.py | 4 -- .../web_platform_tests/prod_config_windows.py | 3 -- .../prod_config_windows_taskcluster.py | 2 - .../mozharness/scripts/fx_desktop_build.py | 1 - testing/mozharness/scripts/release/updates.py | 3 -- 40 files changed, 1 insertion(+), 106 deletions(-) delete mode 100644 taskcluster/docker/recipes/oauth.txt diff --git a/build/mozconfig.cache b/build/mozconfig.cache index e2d072a375e4..e4bfb26ff4d8 100644 --- a/build/mozconfig.cache +++ b/build/mozconfig.cache @@ -4,40 +4,7 @@ # Setup for build cache -# Avoid duplication if the file happens to be included twice. -if test -z "$bucket" -a -z "$NO_CACHE"; then - -bucket= -if test -z "$SCCACHE_DISABLE"; then - case "${branch}" in - try) - case "${master}" in - *scl1.mozilla.com*|*.scl3.mozilla.com*) - bucket=mozilla-releng-s3-cache-us-west-1-try - ;; - *use1.mozilla.com*) - bucket=mozilla-releng-s3-cache-us-east-1-try - ;; - *usw2.mozilla.com*) - bucket=mozilla-releng-s3-cache-us-west-2-try - ;; - esac - ;; - autoland|mozilla-inbound) - case "${master}" in - *use1.mozilla.com*) - bucket=mozilla-releng-s3-cache-us-east-1-prod - ;; - *usw2.mozilla.com*) - bucket=mozilla-releng-s3-cache-us-west-2-prod - ;; - esac - ;; - esac -fi -fi - -# builds where buildprops didn't have the data (eg: taskcluster or non-buildbot) and without sccache disabled: +# builds where buildprops didn't have the data (eg: taskcluster) and without sccache disabled: if test -z "$bucket" -a -z "$SCCACHE_DISABLE"; then # prevent rerun if az is set, or wget is not available @@ -125,5 +92,3 @@ if test -n "$bucket"; then ;; esac fi - -fi diff --git a/taskcluster/docker/android-build/Dockerfile b/taskcluster/docker/android-build/Dockerfile index ac86a89c2eb3..28387c780177 100644 --- a/taskcluster/docker/android-build/Dockerfile +++ b/taskcluster/docker/android-build/Dockerfile @@ -41,13 +41,6 @@ RUN apt-get update && \ # %include taskcluster/docker/recipes/xvfb.sh COPY topsrcdir/taskcluster/docker/recipes/xvfb.sh /builds/worker/scripts/xvfb.sh -# Stubbed out credentials; mozharness looks for this file an issues a WARNING -# if it's not found, which causes the build to fail. Note that this needs to -# be in the parent of the workspace directory and in the directory where -# mozharness is run (not its --work-dir). See Bug 1169652. -# %include taskcluster/docker/recipes/oauth.txt -COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ - # Reset user/workdir from parent image so we can install software. WORKDIR / USER root diff --git a/taskcluster/docker/debian7-build/Dockerfile b/taskcluster/docker/debian7-build/Dockerfile index d725d3368a94..f9fa6f167be4 100644 --- a/taskcluster/docker/debian7-build/Dockerfile +++ b/taskcluster/docker/debian7-build/Dockerfile @@ -60,10 +60,3 @@ RUN apt-get update && \ # Add wrapper scripts for xvfb allowing tasks to easily retry starting up xvfb # %include taskcluster/docker/recipes/xvfb.sh COPY topsrcdir/taskcluster/docker/recipes/xvfb.sh /builds/worker/scripts/xvfb.sh - -# Stubbed out credentials; mozharness looks for this file an issues a WARNING -# if it's not found, which causes the build to fail. Note that this needs to -# be in the parent of the workspace directory and in the directory where -# mozharness is run (not its --work-dir). See Bug 1169652. -# %include taskcluster/docker/recipes/oauth.txt -COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ diff --git a/taskcluster/docker/mingw32-build/Dockerfile b/taskcluster/docker/mingw32-build/Dockerfile index c9956fe108dd..7d0bd67289f4 100644 --- a/taskcluster/docker/mingw32-build/Dockerfile +++ b/taskcluster/docker/mingw32-build/Dockerfile @@ -39,10 +39,3 @@ RUN apt-get update && \ zlib1g-dev \ libfreetype6-dev:i386 \ libx11-dev:i386 - -# Stubbed out credentials; mozharness looks for this file an issues a WARNING -# if it's not found, which causes the build to fail. Note that this needs to -# be in the parent of the workspace directory and in the directory where -# mozharness is run (not its --work-dir). See Bug 1169652. -# %include taskcluster/docker/recipes/oauth.txt -COPY topsrcdir/taskcluster/docker/recipes/oauth.txt /builds/worker/ diff --git a/taskcluster/docker/recipes/oauth.txt b/taskcluster/docker/recipes/oauth.txt deleted file mode 100644 index e56c71f577cc..000000000000 --- a/taskcluster/docker/recipes/oauth.txt +++ /dev/null @@ -1,2 +0,0 @@ -taskcluster_clientId = None -taskcluster_accessToken = None diff --git a/testing/mozharness/configs/awsy/linux_config.py b/testing/mozharness/configs/awsy/linux_config.py index 03e521d6ec27..43d79c90f2a7 100644 --- a/testing/mozharness/configs/awsy/linux_config.py +++ b/testing/mozharness/configs/awsy/linux_config.py @@ -33,7 +33,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/awsy/macosx_config.py b/testing/mozharness/configs/awsy/macosx_config.py index e93fe53263b8..ce3a1e7f2ba3 100644 --- a/testing/mozharness/configs/awsy/macosx_config.py +++ b/testing/mozharness/configs/awsy/macosx_config.py @@ -26,7 +26,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/marionette/prod_config.py b/testing/mozharness/configs/marionette/prod_config.py index f398829f0dba..aeb8d58f7e41 100644 --- a/testing/mozharness/configs/marionette/prod_config.py +++ b/testing/mozharness/configs/marionette/prod_config.py @@ -1,6 +1,4 @@ # This is a template config file for marionette production. -import os - HG_SHARE_BASE_DIR = "/builds/hg-shared" config = { @@ -20,7 +18,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_symbols": "ondemand", "download_minidump_stackwalk": True, "tooltool_cache": "/builds/worker/tooltool-cache", diff --git a/testing/mozharness/configs/marionette/windows_config.py b/testing/mozharness/configs/marionette/windows_config.py index 2aff66b8b862..316668b9bbdf 100644 --- a/testing/mozharness/configs/marionette/windows_config.py +++ b/testing/mozharness/configs/marionette/windows_config.py @@ -1,6 +1,4 @@ # This is a template config file for marionette production on Windows. -import os - config = { # marionette options "marionette_address": "localhost:2828", @@ -22,7 +20,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "download_symbols": "ondemand", "suite_definitions": { diff --git a/testing/mozharness/configs/marionette/windows_taskcluster_config.py b/testing/mozharness/configs/marionette/windows_taskcluster_config.py index be20ea73e326..90a236408f08 100644 --- a/testing/mozharness/configs/marionette/windows_taskcluster_config.py +++ b/testing/mozharness/configs/marionette/windows_taskcluster_config.py @@ -23,7 +23,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": 'C:/builds/oauth.txt', "download_minidump_stackwalk": True, "download_symbols": "ondemand", "suite_definitions": { diff --git a/testing/mozharness/configs/raptor/linux64_config_taskcluster.py b/testing/mozharness/configs/raptor/linux64_config_taskcluster.py index 4dec01ee51a0..6cdbb069f9cf 100644 --- a/testing/mozharness/configs/raptor/linux64_config_taskcluster.py +++ b/testing/mozharness/configs/raptor/linux64_config_taskcluster.py @@ -35,7 +35,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/raptor/linux_config.py b/testing/mozharness/configs/raptor/linux_config.py index 26a8b68153f9..6249608070fe 100644 --- a/testing/mozharness/configs/raptor/linux_config.py +++ b/testing/mozharness/configs/raptor/linux_config.py @@ -31,7 +31,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/raptor/mac_config.py b/testing/mozharness/configs/raptor/mac_config.py index b1763a0f2fa1..9519eee029da 100644 --- a/testing/mozharness/configs/raptor/mac_config.py +++ b/testing/mozharness/configs/raptor/mac_config.py @@ -40,7 +40,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/raptor/windows_config.py b/testing/mozharness/configs/raptor/windows_config.py index 2c507d54a1c5..aee64ef0c307 100644 --- a/testing/mozharness/configs/raptor/windows_config.py +++ b/testing/mozharness/configs/raptor/windows_config.py @@ -37,7 +37,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/raptor/windows_vm_config.py b/testing/mozharness/configs/raptor/windows_vm_config.py index 2568ffccc159..0382f66cf5bc 100644 --- a/testing/mozharness/configs/raptor/windows_vm_config.py +++ b/testing/mozharness/configs/raptor/windows_vm_config.py @@ -36,7 +36,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/single_locale/ash_android-api-16.py b/testing/mozharness/configs/single_locale/ash_android-api-16.py index a0793d8b7cd3..b31a381ea95a 100644 --- a/testing/mozharness/configs/single_locale/ash_android-api-16.py +++ b/testing/mozharness/configs/single_locale/ash_android-api-16.py @@ -14,7 +14,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/autoland_android-api-16.py b/testing/mozharness/configs/single_locale/autoland_android-api-16.py index e67a80016cb7..a458dc396255 100644 --- a/testing/mozharness/configs/single_locale/autoland_android-api-16.py +++ b/testing/mozharness/configs/single_locale/autoland_android-api-16.py @@ -16,7 +16,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/jamun_android-api-16.py b/testing/mozharness/configs/single_locale/jamun_android-api-16.py index 62c6a3408701..b09c3500e958 100644 --- a/testing/mozharness/configs/single_locale/jamun_android-api-16.py +++ b/testing/mozharness/configs/single_locale/jamun_android-api-16.py @@ -13,7 +13,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/maple_android-api-16.py b/testing/mozharness/configs/single_locale/maple_android-api-16.py index 6aa4cb4a1940..9b990b4dd7a4 100644 --- a/testing/mozharness/configs/single_locale/maple_android-api-16.py +++ b/testing/mozharness/configs/single_locale/maple_android-api-16.py @@ -14,7 +14,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py b/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py index af338a319462..61c381a05917 100644 --- a/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py +++ b/testing/mozharness/configs/single_locale/mozilla-aurora_android-api-16.py @@ -16,7 +16,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py b/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py index fbf41d2dc53b..451b44d8f0c6 100644 --- a/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py +++ b/testing/mozharness/configs/single_locale/mozilla-beta_android-api-16.py @@ -15,7 +15,6 @@ config = { "locales_dir": "mobile/android/locales", "locales_platform": "android-api-16", "ignore_locales": ["en-US"], - "balrog_credentials_file": "oauth.txt", "tools_repo": "https://hg.mozilla.org/build/tools", "platform": "android", "is_release_or_beta": True, diff --git a/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py b/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py index cba4ca3b2ef8..4863ef84dff6 100644 --- a/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py +++ b/testing/mozharness/configs/single_locale/mozilla-central_android-api-16.py @@ -16,7 +16,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/mozilla-inbound_android-api-16.py b/testing/mozharness/configs/single_locale/mozilla-inbound_android-api-16.py index 4bf5787511eb..aaa0994672de 100644 --- a/testing/mozharness/configs/single_locale/mozilla-inbound_android-api-16.py +++ b/testing/mozharness/configs/single_locale/mozilla-inbound_android-api-16.py @@ -16,7 +16,6 @@ config = { "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], "nightly_build": True, - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py b/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py index e3749810fe29..e6a60ae419d8 100644 --- a/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py +++ b/testing/mozharness/configs/single_locale/mozilla-release_android-api-16.py @@ -15,7 +15,6 @@ config = { "locales_dir": "mobile/android/locales", "locales_platform": "android-api-16", "ignore_locales": ["en-US"], - "balrog_credentials_file": "oauth.txt", "tools_repo": "https://hg.mozilla.org/build/tools", "platform": "android", "is_release_or_beta": True, diff --git a/testing/mozharness/configs/single_locale/try_android-api-16.py b/testing/mozharness/configs/single_locale/try_android-api-16.py index e0b8289422e8..c8a36e60e1cc 100644 --- a/testing/mozharness/configs/single_locale/try_android-api-16.py +++ b/testing/mozharness/configs/single_locale/try_android-api-16.py @@ -13,7 +13,6 @@ config = { "locales_file": "%s/mobile/locales/l10n-changesets.json" % MOZILLA_DIR, "locales_dir": "mobile/android/locales", "ignore_locales": ["en-US"], - 'balrog_credentials_file': 'oauth.txt', "tools_repo": "https://hg.mozilla.org/build/tools", "tooltool_config": { "manifest": "mobile/android/config/tooltool-manifests/android/releng.manifest", diff --git a/testing/mozharness/configs/talos/linux64_config_taskcluster.py b/testing/mozharness/configs/talos/linux64_config_taskcluster.py index c8bdd8e16ca1..13dce466cf94 100644 --- a/testing/mozharness/configs/talos/linux64_config_taskcluster.py +++ b/testing/mozharness/configs/talos/linux64_config_taskcluster.py @@ -36,7 +36,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/talos/linux_config.py b/testing/mozharness/configs/talos/linux_config.py index 5528e8127ae9..fd0f63195789 100644 --- a/testing/mozharness/configs/talos/linux_config.py +++ b/testing/mozharness/configs/talos/linux_config.py @@ -26,7 +26,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/talos/mac_config.py b/testing/mozharness/configs/talos/mac_config.py index 157c7cab8205..5021eb4a46c9 100644 --- a/testing/mozharness/configs/talos/mac_config.py +++ b/testing/mozharness/configs/talos/mac_config.py @@ -36,7 +36,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/talos/windows_config.py b/testing/mozharness/configs/talos/windows_config.py index 9d90b7241aa0..6c32a9bf9d9c 100644 --- a/testing/mozharness/configs/talos/windows_config.py +++ b/testing/mozharness/configs/talos/windows_config.py @@ -28,7 +28,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/talos/windows_taskcluster_config.py b/testing/mozharness/configs/talos/windows_taskcluster_config.py index 9c909db5ddaa..c7f1363c6001 100644 --- a/testing/mozharness/configs/talos/windows_taskcluster_config.py +++ b/testing/mozharness/configs/talos/windows_taskcluster_config.py @@ -25,7 +25,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": 'C:/builds/oauth.txt', "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('Y:\\', 'tooltool-cache'), diff --git a/testing/mozharness/configs/talos/windows_vm_config.py b/testing/mozharness/configs/talos/windows_vm_config.py index 51ac393ea7ae..d092ff70635d 100644 --- a/testing/mozharness/configs/talos/windows_vm_config.py +++ b/testing/mozharness/configs/talos/windows_vm_config.py @@ -27,7 +27,6 @@ config = { "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index 649349b70a57..322bec9e8399 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -279,7 +279,6 @@ config = { "jittest": [], "mozbase": [], }, - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index 5c285107dcc5..aa3e695ab5b5 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -228,7 +228,6 @@ config = { "jittest": [], "mozbase": [], }, - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/unittests/win_taskcluster_unittest.py b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py index 750e22865ef2..802800648174 100644 --- a/testing/mozharness/configs/unittests/win_taskcluster_unittest.py +++ b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py @@ -297,7 +297,6 @@ config = { "https://blobupload.elasticbeanstalk.com", ], "structured_suites": ["reftest"], - 'blob_uploader_auth_file': 'C:/builds/oauth.txt', "download_minidump_stackwalk": True, "minidump_stackwalk_path": "win32-minidump_stackwalk.exe", "minidump_tooltool_manifest_path": "config/tooltool-manifests/win32/releng.manifest", diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index d46148028597..f20a8139993b 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -255,7 +255,6 @@ config = { "jittest": [], "mozbase": [], }, - "blob_uploader_auth_file": os.path.join(os.getcwd(), "oauth.txt"), "download_minidump_stackwalk": True, "minidump_stackwalk_path": "win32-minidump_stackwalk.exe", "minidump_tooltool_manifest_path": "config/tooltool-manifests/win32/releng.manifest", diff --git a/testing/mozharness/configs/web_platform_tests/prod_config.py b/testing/mozharness/configs/web_platform_tests/prod_config.py index 721c7858c18e..a22c9908a722 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config.py @@ -3,8 +3,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. # ***** END LICENSE BLOCK ***** -import os - config = { "options": [ "--prefs-root=%(test_path)s/prefs", @@ -20,8 +18,6 @@ config = { "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), - "download_minidump_stackwalk": True, # this would normally be in "exes", but "exes" is clobbered by remove_executables diff --git a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py index 4c9462a89515..ba75fbf19323 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py @@ -6,7 +6,6 @@ # This is a template config file for web-platform-tests test. -import os import sys config = { @@ -29,8 +28,6 @@ config = { "https://blobupload.elasticbeanstalk.com", ], - "blob_uploader_auth_file" : os.path.join(os.getcwd(), "oauth.txt"), - "download_minidump_stackwalk": True, "per_test_category": "web-platform", diff --git a/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py b/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py index 31f9fef4b791..57071c53886b 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py @@ -54,8 +54,6 @@ config = { } ], - "blob_uploader_auth_file" : 'C:/builds/oauth.txt', - "download_minidump_stackwalk": True, "per_test_category": "web-platform", diff --git a/testing/mozharness/scripts/fx_desktop_build.py b/testing/mozharness/scripts/fx_desktop_build.py index c009892b1fcb..fa56f1cbc872 100755 --- a/testing/mozharness/scripts/fx_desktop_build.py +++ b/testing/mozharness/scripts/fx_desktop_build.py @@ -53,7 +53,6 @@ class FxDesktopBuild(BuildScript, TryToolsMixin, object): "pgo_platforms": ['linux', 'linux64', 'win32', 'win64'], # nightly stuff "nightly_build": False, - 'balrog_credentials_file': 'oauth.txt', # hg tool stuff "tools_repo": "https://hg.mozilla.org/build/tools", # Seed all clones with mozilla-unified. This ensures subsequent diff --git a/testing/mozharness/scripts/release/updates.py b/testing/mozharness/scripts/release/updates.py index 51817721ab1d..2d236b233db5 100755 --- a/testing/mozharness/scripts/release/updates.py +++ b/testing/mozharness/scripts/release/updates.py @@ -76,9 +76,6 @@ class UpdatesBumper(MercurialScript, AutomationMixin, 'push', 'submit-to-balrog', ], - config={ - 'credentials_file': 'oauth.txt', - }, require_config_file=require_config_file ) From 5003a1911dbf136cd36f1e566d1a5abc240333f5 Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Mon, 28 May 2018 11:13:28 -0400 Subject: [PATCH 047/116] Bug 1237182: Clean up codecoverage property helpers r=tomprince Differential Revision: https://phabricator.services.mozilla.com/D1445 --HG-- extra : rebase_source : 266f33f09347052e24e791d0533fbcc1afb0d1e5 --- .../mozharness/mozilla/testing/codecoverage.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py index e35cc18c9eff..dd53c84304f7 100644 --- a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py +++ b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py @@ -64,8 +64,7 @@ class CodeCoverageMixin(SingleTestMixin): @property def code_coverage_enabled(self): try: - if self.config.get('code_coverage'): - return True + return bool(self.config.get('code_coverage')) except (AttributeError, KeyError, TypeError): return False @@ -79,17 +78,14 @@ class CodeCoverageMixin(SingleTestMixin): @property def ccov_upload_disabled(self): try: - if self.config.get('disable_ccov_upload'): - return True - return False + return bool(self.config.get('disable_ccov_upload')) except (AttributeError, KeyError, TypeError): return False @property def jsd_code_coverage_enabled(self): try: - if self.config.get('jsd_code_coverage'): - return True + return bool(self.config.get('jsd_code_coverage')) except (AttributeError, KeyError, TypeError): return False From 18d2ec17d8bc641fdac2e7b5b2a2653658d5a34a Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Mon, 28 May 2018 13:43:50 -0400 Subject: [PATCH 048/116] Bug 1237182: Remove unused try message handling r=tomprince Differential Revision: https://phabricator.services.mozilla.com/D1446 --HG-- extra : rebase_source : 1cf2a34eab4204c93e33f62e6b8fe46c3253c39e --- .../mozharness/mozilla/testing/try_tools.py | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/testing/try_tools.py b/testing/mozharness/mozharness/mozilla/testing/try_tools.py index 9db012c2e4cc..3d23a04fa1f2 100644 --- a/testing/mozharness/mozharness/mozilla/testing/try_tools.py +++ b/testing/mozharness/mozharness/mozilla/testing/try_tools.py @@ -86,26 +86,6 @@ class TryToolsMixin(TransferMixin): msg = self.config["try_message"] elif 'TRY_COMMIT_MSG' in os.environ: msg = os.environ['TRY_COMMIT_MSG'] - elif self._is_try(): - # This commit message was potentially truncated or not available - # (e.g. if running in TaskCluster), get the full message from hg. - repo_url = 'https://hg.mozilla.org/%s/' - rev = os.environ.get('GECKO_HEAD_REV') - repo_path = self.config.get('branch') - if repo_path: - repo_url = repo_url % repo_path - else: - repo_url = os.environ.get('GECKO_HEAD_REPOSITORY', - repo_url % 'try') - if not repo_url.endswith('/'): - repo_url += '/' - - url = '{}json-pushes?changeset={}&full=1'.format(repo_url, rev) - - pushinfo = self.load_json_from_url(url) - for k, v in pushinfo.items(): - if isinstance(v, dict) and 'changesets' in v: - msg = v['changesets'][-1]['desc'] if not msg: self.warning('Try message not found.') From 94af15e2bbf55e8a303cae33725554f5e366530c Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Mon, 28 May 2018 13:58:47 -0400 Subject: [PATCH 049/116] Bug 1237182: Remove set_property(..., write_to_file) support r=tomprince,Callek Differential Revision: https://phabricator.services.mozilla.com/D1447 --HG-- extra : rebase_source : 9e25457f4846f568694d6e8cf38346adfe4401cf --- testing/mozharness/mozharness/mozilla/automation.py | 5 +---- .../mozharness/mozilla/building/buildbase.py | 10 ++++------ .../mozharness/mozharness/mozilla/testing/testbase.py | 5 ++--- testing/mozharness/scripts/desktop_l10n.py | 6 ++---- testing/mozharness/scripts/mobile_l10n.py | 7 +++---- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/testing/mozharness/mozharness/mozilla/automation.py b/testing/mozharness/mozharness/mozilla/automation.py index c6938d88678c..6cb9eafe8eab 100644 --- a/testing/mozharness/mozharness/mozilla/automation.py +++ b/testing/mozharness/mozharness/mozilla/automation.py @@ -64,12 +64,9 @@ class AutomationMixin(object): if set_return_code: self.return_code = EXIT_STATUS_DICT[self.worst_status] - def set_property(self, prop_name, prop_value, write_to_file=False): + def set_property(self, prop_name, prop_value): self.info("Setting property %s to %s" % (prop_name, prop_value)) self.properties[prop_name] = prop_value - if write_to_file: - return self.dump_properties(prop_list=[prop_name], - file_name=prop_name) return self.properties[prop_name] def query_property(self, prop_name): diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py index 21fceb18eea9..0527a99e5d94 100755 --- a/testing/mozharness/mozharness/mozilla/building/buildbase.py +++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py @@ -840,7 +840,7 @@ or run without that action (ie: --no-{action})" buildid = generate_build_ID() if c.get('is_automation') or os.environ.get("TASK_ID"): - self.set_property('buildid', buildid, write_to_file=True) + self.set_property('buildid', buildid) self.buildid = buildid return self.buildid @@ -1104,7 +1104,7 @@ or run without that action (ie: --no-{action})" self.info(pprint.pformat(build_props)) for key, prop in build_props.iteritems(): if prop != 'UNKNOWN': - self.set_property(key, prop, write_to_file=True) + self.set_property(key, prop) else: self.info("No mach_build_properties.json found - not importing properties.") @@ -1155,9 +1155,7 @@ or run without that action (ie: --no-{action})" base_cmd + [prop['ini_name']], cwd=dirs['abs_obj_dir'], halt_on_failure=halt_on_failure, env=env ) - self.set_property(prop['prop_name'], - prop_val, - write_to_file=True) + self.set_property(prop['prop_name'], prop_val) if self.config.get('is_automation'): self.info("Verifying buildid from application.ini matches buildid " @@ -1321,7 +1319,7 @@ or run without that action (ie: --no-{action})" cwd=objdir, halt_on_failure=True, output_parser=parser) for prop in parser.matches: - self.set_property(prop, parser.matches[prop], write_to_file=True) + self.set_property(prop, parser.matches[prop]) upload_files_cmd = [ 'make', 'echo-variable-UPLOAD_FILES', diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index 7437e792642b..d5655a3aadf7 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -405,7 +405,7 @@ You can set this by specifying --test-url URL parent_dir=dirs['abs_work_dir'], error_level=FATAL) self.installer_path = os.path.realpath(source) - self.set_property("build_url", self.installer_url, write_to_file=True) + self.set_property("build_url", self.installer_url) def _download_and_extract_symbols(self): dirs = self.query_abs_dirs() @@ -428,8 +428,7 @@ You can set this by specifying --test-url URL if not self.symbols_path: self.symbols_path = os.path.join(dirs['abs_work_dir'], 'symbols') - self.set_property("symbols_url", self.symbols_url, - write_to_file=True) + self.set_property("symbols_url", self.symbols_url) if self.symbols_url: self.download_unpack(self.symbols_url, self.symbols_path) diff --git a/testing/mozharness/scripts/desktop_l10n.py b/testing/mozharness/scripts/desktop_l10n.py index a72688f2d29f..2a90c267c09d 100755 --- a/testing/mozharness/scripts/desktop_l10n.py +++ b/testing/mozharness/scripts/desktop_l10n.py @@ -474,7 +474,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, AutomationMixin, prop_value = "%s %s" % (prop_value, message) else: prop_value = message - self.set_property(prop_key, prop_value, write_to_file=True) + self.set_property(prop_key, prop_value) BaseScript.add_failure(self, locale, message=message, **kwargs) def query_failed_locales(self): @@ -488,9 +488,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, AutomationMixin, locales = self.query_locales() for locale in locales: self.locales_property.setdefault(locale, SUCCESS_STR) - self.set_property("locales", - json.dumps(self.locales_property), - write_to_file=True) + self.set_property("locales", json.dumps(self.locales_property)) # Actions {{{2 def pull(self): diff --git a/testing/mozharness/scripts/mobile_l10n.py b/testing/mozharness/scripts/mobile_l10n.py index 797e6a45d1e0..8db64d711517 100755 --- a/testing/mozharness/scripts/mobile_l10n.py +++ b/testing/mozharness/scripts/mobile_l10n.py @@ -343,7 +343,7 @@ class MobileSingleLocale(LocalesMixin, ReleaseMixin, prop_value = "%s %s" % (prop_value, message) else: prop_value = message - self.set_property(prop_key, prop_value, write_to_file=True) + self.set_property(prop_key, prop_value) MercurialScript.add_failure(self, locale, message=message, **kwargs) def summary(self): @@ -352,8 +352,7 @@ class MobileSingleLocale(LocalesMixin, ReleaseMixin, locales = self.query_locales() for locale in locales: self.locales_property.setdefault(locale, "Success") - self.set_property("locales", json.dumps(self.locales_property), - write_to_file=True) + self.set_property("locales", json.dumps(self.locales_property)) # Actions {{{2 def pull(self): @@ -557,7 +556,7 @@ class MobileSingleLocale(LocalesMixin, ReleaseMixin, 'dest': dirs['abs_tools_dir'], }] rev = self.vcs_checkout(**repos[0]) - self.set_property("tools_revision", rev, write_to_file=True) + self.set_property("tools_revision", rev) def query_apkfile_path(self, locale): From 6e2a8646fd5ccbcf493c6ea4bafb193daf6b6184 Mon Sep 17 00:00:00 2001 From: Chris AtLee Date: Thu, 31 May 2018 08:47:06 -0400 Subject: [PATCH 050/116] Bug 1237182: Remove default_blob_upload_servers r=mtabara Differential Revision: https://phabricator.services.mozilla.com/D1474 --HG-- extra : rebase_source : fde7e44495a2d9f5752ab9232c00743e539c49a4 --- testing/mozharness/configs/awsy/linux_config.py | 3 --- testing/mozharness/configs/awsy/macosx_config.py | 3 --- .../mozharness/configs/marionette/prod_config.py | 3 --- .../configs/marionette/windows_config.py | 3 --- .../marionette/windows_taskcluster_config.py | 3 --- .../configs/raptor/linux64_config_taskcluster.py | 3 --- testing/mozharness/configs/raptor/linux_config.py | 3 --- testing/mozharness/configs/raptor/mac_config.py | 3 --- .../mozharness/configs/raptor/windows_config.py | 3 --- .../configs/raptor/windows_vm_config.py | 3 --- .../configs/talos/linux64_config_taskcluster.py | 3 --- testing/mozharness/configs/talos/linux_config.py | 3 --- testing/mozharness/configs/talos/mac_config.py | 3 --- .../mozharness/configs/talos/windows_config.py | 3 --- .../configs/talos/windows_taskcluster_config.py | 3 --- .../mozharness/configs/talos/windows_vm_config.py | 3 --- .../configs/unittests/linux_unittest.py | 15 ++++++--------- .../mozharness/configs/unittests/mac_unittest.py | 15 ++++++--------- .../configs/unittests/win_taskcluster_unittest.py | 3 --- .../mozharness/configs/unittests/win_unittest.py | 15 ++++++--------- .../configs/web_platform_tests/prod_config.py | 4 ---- .../web_platform_tests/prod_config_windows.py | 4 ---- .../prod_config_windows_taskcluster.py | 4 ---- 23 files changed, 18 insertions(+), 90 deletions(-) diff --git a/testing/mozharness/configs/awsy/linux_config.py b/testing/mozharness/configs/awsy/linux_config.py index 43d79c90f2a7..4dad087f7a7a 100644 --- a/testing/mozharness/configs/awsy/linux_config.py +++ b/testing/mozharness/configs/awsy/linux_config.py @@ -30,9 +30,6 @@ config = { "install", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/awsy/macosx_config.py b/testing/mozharness/configs/awsy/macosx_config.py index ce3a1e7f2ba3..b60b09bb61a3 100644 --- a/testing/mozharness/configs/awsy/macosx_config.py +++ b/testing/mozharness/configs/awsy/macosx_config.py @@ -23,9 +23,6 @@ config = { "install", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/marionette/prod_config.py b/testing/mozharness/configs/marionette/prod_config.py index aeb8d58f7e41..f2872ebef539 100644 --- a/testing/mozharness/configs/marionette/prod_config.py +++ b/testing/mozharness/configs/marionette/prod_config.py @@ -15,9 +15,6 @@ config = { 'install', 'run-tests', ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_symbols": "ondemand", "download_minidump_stackwalk": True, "tooltool_cache": "/builds/worker/tooltool-cache", diff --git a/testing/mozharness/configs/marionette/windows_config.py b/testing/mozharness/configs/marionette/windows_config.py index 316668b9bbdf..c3d997f1c154 100644 --- a/testing/mozharness/configs/marionette/windows_config.py +++ b/testing/mozharness/configs/marionette/windows_config.py @@ -17,9 +17,6 @@ config = { 'install', 'run-tests', ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "download_symbols": "ondemand", "suite_definitions": { diff --git a/testing/mozharness/configs/marionette/windows_taskcluster_config.py b/testing/mozharness/configs/marionette/windows_taskcluster_config.py index 90a236408f08..c346537544b4 100644 --- a/testing/mozharness/configs/marionette/windows_taskcluster_config.py +++ b/testing/mozharness/configs/marionette/windows_taskcluster_config.py @@ -20,9 +20,6 @@ config = { 'install', 'run-tests', ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "download_symbols": "ondemand", "suite_definitions": { diff --git a/testing/mozharness/configs/raptor/linux64_config_taskcluster.py b/testing/mozharness/configs/raptor/linux64_config_taskcluster.py index 6cdbb069f9cf..3d7e95e2fbe7 100644 --- a/testing/mozharness/configs/raptor/linux64_config_taskcluster.py +++ b/testing/mozharness/configs/raptor/linux64_config_taskcluster.py @@ -32,9 +32,6 @@ config = { "install", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/raptor/linux_config.py b/testing/mozharness/configs/raptor/linux_config.py index 6249608070fe..4b699c7d7c8c 100644 --- a/testing/mozharness/configs/raptor/linux_config.py +++ b/testing/mozharness/configs/raptor/linux_config.py @@ -28,9 +28,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/raptor/mac_config.py b/testing/mozharness/configs/raptor/mac_config.py index 9519eee029da..6ccecc4d2a9d 100644 --- a/testing/mozharness/configs/raptor/mac_config.py +++ b/testing/mozharness/configs/raptor/mac_config.py @@ -37,9 +37,6 @@ config = { "postflight_run_cmd_suites": [ SCREEN_RESOLUTION_CHECK, ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/raptor/windows_config.py b/testing/mozharness/configs/raptor/windows_config.py index aee64ef0c307..63c4fac8693c 100644 --- a/testing/mozharness/configs/raptor/windows_config.py +++ b/testing/mozharness/configs/raptor/windows_config.py @@ -34,9 +34,6 @@ config = { "install", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/raptor/windows_vm_config.py b/testing/mozharness/configs/raptor/windows_vm_config.py index 0382f66cf5bc..19bac9661482 100644 --- a/testing/mozharness/configs/raptor/windows_vm_config.py +++ b/testing/mozharness/configs/raptor/windows_vm_config.py @@ -33,9 +33,6 @@ config = { "install", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/talos/linux64_config_taskcluster.py b/testing/mozharness/configs/talos/linux64_config_taskcluster.py index 13dce466cf94..50d61be633a1 100644 --- a/testing/mozharness/configs/talos/linux64_config_taskcluster.py +++ b/testing/mozharness/configs/talos/linux64_config_taskcluster.py @@ -33,9 +33,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/talos/linux_config.py b/testing/mozharness/configs/talos/linux_config.py index fd0f63195789..301cfd867fda 100644 --- a/testing/mozharness/configs/talos/linux_config.py +++ b/testing/mozharness/configs/talos/linux_config.py @@ -23,9 +23,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/talos/mac_config.py b/testing/mozharness/configs/talos/mac_config.py index 5021eb4a46c9..7b648a6dfcc1 100644 --- a/testing/mozharness/configs/talos/mac_config.py +++ b/testing/mozharness/configs/talos/mac_config.py @@ -33,9 +33,6 @@ config = { "postflight_run_cmd_suites": [ SCREEN_RESOLUTION_CHECK, ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/talos/windows_config.py b/testing/mozharness/configs/talos/windows_config.py index 6c32a9bf9d9c..dc2e02ac1c90 100644 --- a/testing/mozharness/configs/talos/windows_config.py +++ b/testing/mozharness/configs/talos/windows_config.py @@ -25,9 +25,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/talos/windows_taskcluster_config.py b/testing/mozharness/configs/talos/windows_taskcluster_config.py index c7f1363c6001..0a0ee51ce07c 100644 --- a/testing/mozharness/configs/talos/windows_taskcluster_config.py +++ b/testing/mozharness/configs/talos/windows_taskcluster_config.py @@ -22,9 +22,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('Y:\\', 'tooltool-cache'), diff --git a/testing/mozharness/configs/talos/windows_vm_config.py b/testing/mozharness/configs/talos/windows_vm_config.py index d092ff70635d..f0b176b1bb0a 100644 --- a/testing/mozharness/configs/talos/windows_vm_config.py +++ b/testing/mozharness/configs/talos/windows_vm_config.py @@ -24,9 +24,6 @@ config = { "setup-mitmproxy", "run-tests", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "metro_harness_path_frmt": "%(metro_base_path)s/metro/metrotestharness.exe", "download_minidump_stackwalk": True, "tooltool_cache": os.path.join('c:\\', 'build', 'tooltool_cache'), diff --git a/testing/mozharness/configs/unittests/linux_unittest.py b/testing/mozharness/configs/unittests/linux_unittest.py index 322bec9e8399..1eeb0587a2e2 100644 --- a/testing/mozharness/configs/unittests/linux_unittest.py +++ b/testing/mozharness/configs/unittests/linux_unittest.py @@ -269,16 +269,13 @@ config = { ], "vcs_output_timeout": 1000, "minidump_save_path": "%(abs_work_dir)s/../minidumps", - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "unstructured_flavors": {"xpcshell": [], - "gtest": [], - "mozmill": [], - "cppunittest": [], - "jittest": [], - "mozbase": [], - }, + "gtest": [], + "mozmill": [], + "cppunittest": [], + "jittest": [], + "mozbase": [], + }, "download_minidump_stackwalk": True, "minidump_stackwalk_path": MINIDUMP_STACKWALK_PATH, "minidump_tooltool_manifest_path": TOOLTOOL_MANIFEST_PATH, diff --git a/testing/mozharness/configs/unittests/mac_unittest.py b/testing/mozharness/configs/unittests/mac_unittest.py index aa3e695ab5b5..8f1f37f770e0 100644 --- a/testing/mozharness/configs/unittests/mac_unittest.py +++ b/testing/mozharness/configs/unittests/mac_unittest.py @@ -218,16 +218,13 @@ config = { ], "vcs_output_timeout": 1000, "minidump_save_path": "%(abs_work_dir)s/../minidumps", - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "unstructured_flavors": {"xpcshell": [], - "gtest": [], - "mozmill": [], - "cppunittest": [], - "jittest": [], - "mozbase": [], - }, + "gtest": [], + "mozmill": [], + "cppunittest": [], + "jittest": [], + "mozbase": [], + }, "download_minidump_stackwalk": True, "minidump_stackwalk_path": "macosx64-minidump_stackwalk", "minidump_tooltool_manifest_path": "config/tooltool-manifests/macosx64/releng.manifest", diff --git a/testing/mozharness/configs/unittests/win_taskcluster_unittest.py b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py index 802800648174..2816edde0ece 100644 --- a/testing/mozharness/configs/unittests/win_taskcluster_unittest.py +++ b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py @@ -293,9 +293,6 @@ config = { ], "vcs_output_timeout": 1000, "minidump_save_path": "%(abs_work_dir)s/../minidumps", - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "structured_suites": ["reftest"], "download_minidump_stackwalk": True, "minidump_stackwalk_path": "win32-minidump_stackwalk.exe", diff --git a/testing/mozharness/configs/unittests/win_unittest.py b/testing/mozharness/configs/unittests/win_unittest.py index f20a8139993b..04829edbc9ac 100644 --- a/testing/mozharness/configs/unittests/win_unittest.py +++ b/testing/mozharness/configs/unittests/win_unittest.py @@ -245,16 +245,13 @@ config = { ], "vcs_output_timeout": 1000, "minidump_save_path": "%(abs_work_dir)s/../minidumps", - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], "unstructured_flavors": {"xpcshell": [], - "gtest": [], - "mozmill": [], - "cppunittest": [], - "jittest": [], - "mozbase": [], - }, + "gtest": [], + "mozmill": [], + "cppunittest": [], + "jittest": [], + "mozbase": [], + }, "download_minidump_stackwalk": True, "minidump_stackwalk_path": "win32-minidump_stackwalk.exe", "minidump_tooltool_manifest_path": "config/tooltool-manifests/win32/releng.manifest", diff --git a/testing/mozharness/configs/web_platform_tests/prod_config.py b/testing/mozharness/configs/web_platform_tests/prod_config.py index a22c9908a722..6493c4d0cf6e 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config.py @@ -14,10 +14,6 @@ config = { "--certutil-binary=%(test_install_path)s/bin/certutil", ], - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], - "download_minidump_stackwalk": True, # this would normally be in "exes", but "exes" is clobbered by remove_executables diff --git a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py index ba75fbf19323..a6549ae3eade 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config_windows.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows.py @@ -24,10 +24,6 @@ config = { 'hg': 'c:/mozilla-build/hg/hg', }, - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], - "download_minidump_stackwalk": True, "per_test_category": "web-platform", diff --git a/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py b/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py index 57071c53886b..6288ac4c5d26 100644 --- a/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py +++ b/testing/mozharness/configs/web_platform_tests/prod_config_windows_taskcluster.py @@ -25,10 +25,6 @@ config = { 'hg': os.path.join(os.environ['PROGRAMFILES'], 'Mercurial', 'hg') }, - "default_blob_upload_servers": [ - "https://blobupload.elasticbeanstalk.com", - ], - "run_cmd_checks_enabled": True, "preflight_run_cmd_suites": [ { From e68fca00eb3f7fd9eaf450748f82715715e084ee Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Fri, 1 Jun 2018 17:54:25 +0200 Subject: [PATCH 051/116] Bug 1466077 - Make all ccov test suites inherit the run-on-projects from their ccov build. r=jmaher --HG-- extra : rebase_source : b6426ce82bd02cdcbd644befa6f53fb81cedc1d6 --- taskcluster/ci/build/linux.yml | 6 +++--- taskcluster/ci/build/windows.yml | 2 +- taskcluster/ci/test/misc.yml | 9 +++++---- taskcluster/ci/test/web-platform.yml | 6 +++--- taskcluster/taskgraph/transforms/tests.py | 18 +++++++++--------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/taskcluster/ci/build/linux.yml b/taskcluster/ci/build/linux.yml index 82964ef4cdf0..bd7f32af1dd8 100644 --- a/taskcluster/ci/build/linux.yml +++ b/taskcluster/ci/build/linux.yml @@ -813,7 +813,7 @@ linux64-jsdcov/opt: platform: linux64-jsdcov/opt symbol: B tier: 2 - run-on-projects: [] + run-on-projects: ['mozilla-central', 'try'] worker-type: aws-provisioner-v1/gecko-{level}-b-linux worker: max-run-time: 36000 @@ -842,7 +842,7 @@ linux64-ccov/debug: platform: linux64-ccov/debug symbol: B tier: 2 - run-on-projects: [] + run-on-projects: ['mozilla-central', 'try'] worker-type: aws-provisioner-v1/gecko-{level}-b-linux worker: max-run-time: 36000 @@ -871,7 +871,7 @@ linux64-ccov/opt: platform: linux64-ccov/opt symbol: B tier: 2 - run-on-projects: [] + run-on-projects: ['try'] worker-type: aws-provisioner-v1/gecko-{level}-b-linux worker: max-run-time: 36000 diff --git a/taskcluster/ci/build/windows.yml b/taskcluster/ci/build/windows.yml index 5c83b822b5bf..9d3b4791ee08 100755 --- a/taskcluster/ci/build/windows.yml +++ b/taskcluster/ci/build/windows.yml @@ -562,7 +562,7 @@ win64-ccov/debug: - builds/taskcluster_base_windows.py - builds/taskcluster_base_win64.py - builds/taskcluster_sub_win64/ccov_debug.py - run-on-projects: [] + run-on-projects: ['mozilla-central', 'try'] toolchains: - win64-clang-cl - win64-rust diff --git a/taskcluster/ci/test/misc.yml b/taskcluster/ci/test/misc.yml index b86c5ffb8d6e..477a80125d62 100644 --- a/taskcluster/ci/test/misc.yml +++ b/taskcluster/ci/test/misc.yml @@ -98,8 +98,9 @@ test-verify: allow-software-gl-layers: false run-on-projects: by-test-platform: - # do not run on ccov; see also the enable_code_coverage transform + # do not run on ccov or jsdcov .*-ccov/.*: [] + .*-jsdcov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] tier: 2 @@ -137,8 +138,9 @@ test-verify-gpu: allow-software-gl-layers: false run-on-projects: by-test-platform: - # do not run on ccov; see also the enable_code_coverage transform + # do not run on ccov or jsdcov .*-ccov/.*: [] + .*-jsdcov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] tier: 2 @@ -173,8 +175,7 @@ test-coverage: allow-software-gl-layers: false run-on-projects: by-test-platform: - # only run on mozilla-central and try. - .*-ccov/.*: ['mozilla-central', 'try'] + .*-ccov/.*: built-projects default: [] tier: 2 mozharness: diff --git a/taskcluster/ci/test/web-platform.yml b/taskcluster/ci/test/web-platform.yml index 7e45a1325b2d..6d3f6f5ec5ca 100644 --- a/taskcluster/ci/test/web-platform.yml +++ b/taskcluster/ci/test/web-platform.yml @@ -141,8 +141,9 @@ test-verify-wpt: max-run-time: 10800 run-on-projects: by-test-platform: - # do not run on ccov; see also the enable_code_coverage transform + # do not run on ccov or jsdcov .*-ccov/.*: [] + .*-jsdcov/.*: [] # do not run on beta or release: usually just confirms earlier results default: ['trunk', 'try'] tier: 2 @@ -157,8 +158,7 @@ test-coverage-wpt: max-run-time: 10800 run-on-projects: by-test-platform: - # only run on mozilla-central and try. - .*-ccov/.*: ['mozilla-central', 'try'] + .*-ccov/.*: built-projects default: [] tier: 2 mozharness: diff --git a/taskcluster/taskgraph/transforms/tests.py b/taskcluster/taskgraph/transforms/tests.py index 43b08f4fc6fc..b9679bd5598a 100644 --- a/taskcluster/taskgraph/transforms/tests.py +++ b/taskcluster/taskgraph/transforms/tests.py @@ -704,13 +704,13 @@ def handle_suite_category(config, tests): def enable_code_coverage(config, tests): """Enable code coverage for the ccov and jsdcov build-platforms""" for test in tests: - if 'ccov' in test['build-platform'] and not test['test-name'].startswith('test-verify'): + if 'ccov' in test['build-platform']: test['mozharness'].setdefault('extra-options', []).append('--code-coverage') test['instance-size'] = 'xlarge' - # Ensure we don't run on inbound/autoland/beta, but if the test is try only, ignore it - if 'mozilla-central' in test['run-on-projects'] or \ - test['run-on-projects'] == 'built-projects': - test['run-on-projects'] = ['mozilla-central', 'try'] + # Ensure we always run on the projects defined by the build, unless the test + # is try only or shouldn't run at all. + if test['run-on-projects'] not in [[], ['try']]: + test['run-on-projects'] = 'built-projects' # Ensure we don't optimize test suites out. # We always want to run all test suites for coverage purposes. @@ -735,10 +735,10 @@ def enable_code_coverage(config, tests): if 'linux' in test['build-platform']: test['docker-image'] = {"in-tree": "desktop1604-test"} elif test['build-platform'] == 'linux64-jsdcov/opt': - # Ensure we don't run on inbound/autoland/beta, but if the test is try only, ignore it - if 'mozilla-central' in test['run-on-projects'] or \ - test['run-on-projects'] == 'built-projects': - test['run-on-projects'] = ['mozilla-central', 'try'] + # Ensure we always run on the projects defined by the build, unless the test + # is try only or shouldn't run at all. + if test['run-on-projects'] not in [[], ['try']]: + test['run-on-projects'] = 'built-projects' test['mozharness'].setdefault('extra-options', []).append('--jsd-code-coverage') yield test From 19aa8a3bac425e1a04730fb68a51485ca08259d4 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 12:17:10 -0400 Subject: [PATCH 052/116] Bug 1465602 part 1. Enforce that the default toJSON can only return 'object'. r=qdot The spec says: The return type of the default toJSON operation must be object. --- dom/bindings/parser/WebIDL.py | 5 +++ dom/bindings/parser/tests/test_toJSON.py | 42 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 021cef58f778..b9c8159d6dc3 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -5131,6 +5131,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): if not self.isToJSON(): raise WebIDLError("[Default] is only allowed on toJSON operations", [attr.location, self.location]) + + if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: + raise WebIDLError("The return type of the default toJSON " + "operation must be 'object'", + [attr.location, self.location]); elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or diff --git a/dom/bindings/parser/tests/test_toJSON.py b/dom/bindings/parser/tests/test_toJSON.py index 4d29b0290685..1a4b08678bee 100644 --- a/dom/bindings/parser/tests/test_toJSON.py +++ b/dom/bindings/parser/tests/test_toJSON.py @@ -41,6 +41,48 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow a toJSON method with arguments.") + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method with 'long' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a default toJSON method with 'object' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.") + parser = parser.reset() threw = False try: From a0ebf6e398df32097b97431f0a14a27cb8ebc353 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 12:17:10 -0400 Subject: [PATCH 053/116] Bug 1465602 part 2. Fix the interaction of default toJSON with Func-controlled exposure that examines the object's global. r=qdot --- dom/bindings/Codegen.py | 29 +++++++++++--- dom/bindings/DOMJSClass.h | 2 + dom/bindings/test/TestFunctions.cpp | 32 ++++++++++++++++ dom/bindings/test/TestFunctions.h | 5 +++ dom/bindings/test/mochitest.ini | 2 + dom/bindings/test/test_toJSON.html | 59 +++++++++++++++++++++++++++++ dom/webidl/TestFunctions.webidl | 8 ++++ 7 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 dom/bindings/test/test_toJSON.html diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 8f6a6f0f838f..1107d5ae1aef 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2869,10 +2869,10 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): Generate the CollectJSONAttributes method for an interface descriptor """ def __init__(self, descriptor, toJSONMethod): - args = [Argument('JSContext*', 'aCx'), + args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'obj'), Argument('%s*' % descriptor.nativeType, 'self'), - Argument('JS::Rooted&', 'aResult')] + Argument('JS::Rooted&', 'result')] CGAbstractMethod.__init__(self, descriptor, 'CollectJSONAttributes', 'bool', args, canRunScript=True) self.toJSONMethod = toJSONMethod @@ -2882,15 +2882,16 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): interface = self.descriptor.interface toJSONCondition = PropertyDefiner.getControllingCondition(self.toJSONMethod, self.descriptor) + needUnwrappedObj = False for m in interface.members: if m.isAttr() and not m.isStatic() and m.type.isJSONType(): getAndDefine = fill( """ - JS::Rooted temp(aCx); - if (!get_${name}(aCx, obj, self, JSJitGetterCallArgs(&temp))) { + JS::Rooted temp(cx); + if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) { return false; } - if (!JS_DefineProperty(aCx, aResult, "${name}", temp, JSPROP_ENUMERATE)) { + if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) { return false; } """, @@ -2901,12 +2902,13 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): # possibly be disabled, but other things might be. condition = PropertyDefiner.getControllingCondition(m, self.descriptor) if condition.hasDisablers() and condition != toJSONCondition: + needUnwrappedObj = True; ret += fill( """ // This is unfortunately a linear scan through sAttributes, but we // only do it for things which _might_ be disabled, which should // help keep the performance problems down. - if (IsGetterEnabled(aCx, obj, (JSJitGetterOp)get_${name}, sAttributes)) { + if (IsGetterEnabled(cx, unwrappedObj, (JSJitGetterOp)get_${name}, sAttributes)) { $*{getAndDefine} } """, @@ -2921,6 +2923,21 @@ class CGCollectJSONAttributesMethod(CGAbstractMethod): """, getAndDefine=getAndDefine) ret += 'return true;\n' + + if needUnwrappedObj: + ret= fill( + """ + JS::Rooted unwrappedObj(cx, js::CheckedUnwrap(obj)); + if (!unwrappedObj) { + // How did that happen? We managed to get called with that + // object as "this"! Just give up on sanity. + return false; + } + + $*{ret} + """, + ret=ret); + return ret diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h index 3d4be7494fa7..7bf3d0cdfc8a 100644 --- a/dom/bindings/DOMJSClass.h +++ b/dom/bindings/DOMJSClass.h @@ -8,6 +8,7 @@ #define mozilla_dom_DOMJSClass_h #include "jsfriendapi.h" +#include "js/Wrapper.h" #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Likely.h" @@ -154,6 +155,7 @@ struct PrefableDisablers { template struct Prefable { inline bool isEnabled(JSContext* cx, JS::Handle obj) const { + MOZ_ASSERT(!js::IsWrapper(obj)); if (MOZ_LIKELY(!disablers)) { return true; } diff --git a/dom/bindings/test/TestFunctions.cpp b/dom/bindings/test/TestFunctions.cpp index 9fa0c3f13633..d1905da762fb 100644 --- a/dom/bindings/test/TestFunctions.cpp +++ b/dom/bindings/test/TestFunctions.cpp @@ -4,6 +4,7 @@ * 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 "mozilla/dom/BindingUtils.h" #include "mozilla/dom/TestFunctions.h" #include "mozilla/dom/TestFunctionsBinding.h" #include "nsStringBuffer.h" @@ -108,6 +109,37 @@ TestFunctions::ThrowToRejectPromise(GlobalObject& aGlobal, ErrorResult& aError) return nullptr; } +int32_t +TestFunctions::One() const +{ + return 1; +} + +int32_t +TestFunctions::Two() const +{ + return 2; +} + +bool +TestFunctions::ObjectFromAboutBlank(JSContext* aCx, JSObject* aObj) +{ + // We purposefully don't use WindowOrNull here, because we want to + // demonstrate the incorrect behavior we get, not just fail some asserts. + RefPtr win; + UNWRAP_OBJECT(Window, aObj, win); + if (!win) { + return false; + } + + nsIDocument* doc = win->GetDoc(); + if (!doc) { + return false; + } + + return doc->GetDocumentURI()->GetSpecOrDefault().EqualsLiteral("about:blank"); +} + bool TestFunctions::WrapObject(JSContext* aCx, JS::Handle aGivenProto, JS::MutableHandle aWrapper) diff --git a/dom/bindings/test/TestFunctions.h b/dom/bindings/test/TestFunctions.h index 01e36566e38e..4772d8841991 100644 --- a/dom/bindings/test/TestFunctions.h +++ b/dom/bindings/test/TestFunctions.h @@ -46,6 +46,11 @@ public: ThrowToRejectPromise(GlobalObject& aGlobal, ErrorResult& aError); + int32_t One() const; + int32_t Two() const; + + static bool ObjectFromAboutBlank(JSContext* aCx, JSObject* aObj); + bool WrapObject(JSContext* aCx, JS::Handle aGivenProto, JS::MutableHandle aWrapper); private: diff --git a/dom/bindings/test/mochitest.ini b/dom/bindings/test/mochitest.ini index 81555953effa..08337b61bf3a 100644 --- a/dom/bindings/test/mochitest.ini +++ b/dom/bindings/test/mochitest.ini @@ -84,3 +84,5 @@ skip-if = debug == false [test_stringBindings.html] skip-if = debug == false [test_jsimplemented_subclassing.html] +[test_toJSON.html] +skip-if = debug == false diff --git a/dom/bindings/test/test_toJSON.html b/dom/bindings/test/test_toJSON.html new file mode 100644 index 000000000000..779bc97ba49f --- /dev/null +++ b/dom/bindings/test/test_toJSON.html @@ -0,0 +1,59 @@ + + + + + + Test for Bug 1465602 + + + + +Mozilla Bug 1465602 +

+ +
+
+ + + diff --git a/dom/webidl/TestFunctions.webidl b/dom/webidl/TestFunctions.webidl index 4321bf1bc48d..9c72392c3701 100644 --- a/dom/webidl/TestFunctions.webidl +++ b/dom/webidl/TestFunctions.webidl @@ -48,4 +48,12 @@ interface TestFunctions { // Throws an InvalidStateError to auto-create a rejected promise. [Throws] static Promise throwToRejectPromise(); + + // Some attributes for the toJSON to work with. + readonly attribute long one; + [Func="mozilla::dom::TestFunctions::ObjectFromAboutBlank"] + readonly attribute long two; + + // Testing for how default toJSON behaves. + [Default] object toJSON(); }; From 6e425cf3827fb294dc1e7d6dbe2add325d4641ee Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 1 Jun 2018 18:03:13 +0100 Subject: [PATCH 054/116] Backed out changeset 36687c035662 (bug 1463115) for frequent mochitest failures on Linux-debug --- dom/base/nsRange.cpp | 11 ++++------ dom/base/nsRange.h | 3 +-- dom/chrome-webidl/InspectorUtils.webidl | 3 +-- layout/base/nsLayoutUtils.cpp | 28 ++++++++----------------- layout/base/nsLayoutUtils.h | 6 ++---- layout/generic/nsTextFrame.h | 4 ++-- layout/inspector/InspectorUtils.cpp | 4 +--- layout/inspector/InspectorUtils.h | 1 - 8 files changed, 20 insertions(+), 40 deletions(-) diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index cde28563c486..5a4f46da60f0 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3157,7 +3157,7 @@ nsRange::GetClientRectsAndTexts( nsresult nsRange::GetUsedFontFaces(nsTArray>& aResult, - uint32_t aMaxRanges, bool aSkipCollapsedWhitespace) + uint32_t aMaxRanges) { NS_ENSURE_TRUE(mStart.Container(), NS_ERROR_UNEXPECTED); @@ -3201,20 +3201,17 @@ nsRange::GetUsedFontFaces(nsTArray>& aResult, int32_t offset = startContainer == endContainer ? mEnd.Offset() : content->GetText()->GetLength(); nsLayoutUtils::GetFontFacesForText(frame, mStart.Offset(), offset, - true, fontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + true, fontFaces, aMaxRanges); continue; } if (node == endContainer) { nsLayoutUtils::GetFontFacesForText(frame, 0, mEnd.Offset(), - true, fontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + true, fontFaces, aMaxRanges); continue; } } - nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges); } // Take ownership of the InspectorFontFaces in the table and move them into diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h index f0ee5496e91d..5e2bae621be2 100644 --- a/dom/base/nsRange.h +++ b/dom/base/nsRange.h @@ -270,8 +270,7 @@ public: // where each face was used). nsresult GetUsedFontFaces( nsTArray>& aResult, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace); + uint32_t aMaxRanges); // nsIMutationObserver methods NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index 1591f92a801b..9f183d504856 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -65,8 +65,7 @@ namespace InspectorUtils { // to access via its .ranges attribute. [NewObject, Throws] sequence getUsedFontFaces( Range range, - optional unsigned long maxRanges = 0, - optional boolean skipCollapsedWhitespace = true); + optional unsigned long maxRanges = 0); sequence getCSSPseudoElementNames(); void addPseudoClassLock(Element element, diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 9e10105deaf6..f07813a589ca 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7851,16 +7851,14 @@ nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot) static void GetFontFacesForFramesInner(nsIFrame* aFrame, nsLayoutUtils::UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace) + uint32_t aMaxRanges) { MOZ_ASSERT(aFrame, "NULL frame pointer"); if (aFrame->IsTextFrame()) { if (!aFrame->GetPrevContinuation()) { nsLayoutUtils::GetFontFacesForText(aFrame, 0, INT32_MAX, true, - aFontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + aFontFaces, aMaxRanges); } return; } @@ -7872,8 +7870,7 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); child = nsPlaceholderFrame::GetRealFrameFor(child); - GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges); } } } @@ -7881,14 +7878,12 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, /* static */ nsresult nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace) + uint32_t aMaxRanges) { MOZ_ASSERT(aFrame, "NULL frame pointer"); while (aFrame) { - GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges, - aSkipCollapsedWhitespace); + GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges); aFrame = GetNextContinuationOrIBSplitSibling(aFrame); } @@ -7959,8 +7954,7 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace) + uint32_t aMaxRanges) { MOZ_ASSERT(aFrame, "NULL frame pointer"); @@ -8000,13 +7994,9 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, } } - if (!aSkipCollapsedWhitespace || - (curr->HasAnyNoncollapsedCharacters() && - curr->HasNonSuppressedText())) { - gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), - iter.ConvertOriginalToSkipped(fend)); - AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); - } + gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), + iter.ConvertOriginalToSkipped(fend)); + AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); curr = next; } while (aFollowContinuations && curr); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 3a4ad0c9dff9..2675847487e8 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2288,8 +2288,7 @@ public: */ static nsresult GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aResult, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace); + uint32_t aMaxRanges); /** * Adds all font faces used within the specified range of text in aFrame, @@ -2303,8 +2302,7 @@ public: int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aResult, - uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace); + uint32_t aMaxRanges); /** * Walks the frame tree starting at aFrame looking for textRuns. diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index af0a9ab14a81..92754a7a92ad 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -666,8 +666,6 @@ public: uint32_t CountGraphemeClusters() const; - bool HasAnyNoncollapsedCharacters() override; - protected: virtual ~nsTextFrame(); @@ -884,6 +882,8 @@ protected: void ClearFrameOffsetCache(); + bool HasAnyNoncollapsedCharacters() override; + void ClearMetrics(ReflowOutput& aMetrics); /** diff --git a/layout/inspector/InspectorUtils.cpp b/layout/inspector/InspectorUtils.cpp index cc09fe684b85..9cef97b5a361 100644 --- a/layout/inspector/InspectorUtils.cpp +++ b/layout/inspector/InspectorUtils.cpp @@ -617,12 +617,10 @@ InspectorUtils::GetCleanComputedStyleForElement(dom::Element* aElement, InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject, nsRange& aRange, uint32_t aMaxRanges, - bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv) { - nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges, - aSkipCollapsedWhitespace); + nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges); if (NS_FAILED(rv)) { aRv.Throw(rv); } diff --git a/layout/inspector/InspectorUtils.h b/layout/inspector/InspectorUtils.h index 0c3f8ec09d55..8efa267b8f42 100644 --- a/layout/inspector/InspectorUtils.h +++ b/layout/inspector/InspectorUtils.h @@ -225,7 +225,6 @@ public: nsRange& aRange, uint32_t aMaxRanges, // max number of ranges to // record for each face - bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv); From d4b7d95206a105fb2b28031627c020daf7944c52 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Fri, 25 May 2018 14:07:57 +0100 Subject: [PATCH 055/116] Bug 1464400 - Keep track of CSS generics when resolving to actual font families and faces, and expose as a new CSSGeneric attribute on InspectorFontFace. r=jwatt --- dom/chrome-webidl/InspectorUtils.webidl | 2 + gfx/thebes/gfxDWriteFontList.cpp | 4 +- gfx/thebes/gfxDWriteFontList.h | 2 +- gfx/thebes/gfxFcPlatformFontList.cpp | 17 ++--- gfx/thebes/gfxFcPlatformFontList.h | 6 +- gfx/thebes/gfxFont.h | 13 ++-- gfx/thebes/gfxFontEntry.h | 25 ++++++++ gfx/thebes/gfxFontFamilyList.h | 2 +- gfx/thebes/gfxGDIFontList.cpp | 4 +- gfx/thebes/gfxGDIFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.h | 2 +- gfx/thebes/gfxMacPlatformFontList.mm | 2 +- gfx/thebes/gfxPlatformFontList.cpp | 19 +++--- gfx/thebes/gfxPlatformFontList.h | 13 ++-- gfx/thebes/gfxTextRun.cpp | 57 +++++++++++------ gfx/thebes/gfxTextRun.h | 28 ++++++--- layout/inspector/InspectorFontFace.cpp | 14 +++++ layout/inspector/InspectorFontFace.h | 1 + layout/inspector/tests/chrome/chrome.ini | 1 + .../tests/chrome/test_fontFaceGeneric.xul | 62 +++++++++++++++++++ layout/style/ServoBindings.h | 2 +- 21 files changed, 214 insertions(+), 64 deletions(-) create mode 100644 layout/inspector/tests/chrome/test_fontFaceGeneric.xul diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index 9f183d504856..a38508e16b8c 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -134,6 +134,8 @@ interface InspectorFontFace { readonly attribute DOMString CSSFamilyName; // a family name that could be used in CSS font-family // (not necessarily the actual name that was used, // due to aliases, generics, localized names, etc) + readonly attribute DOMString CSSGeneric; // CSS generic (serif, sans-serif, etc) that was mapped + // to this font, if any (frequently empty!) [NewObject,Throws] sequence getVariationAxes(); [NewObject,Throws] sequence getVariationInstances(); diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 06133658c765..e29f030f5be8 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1426,7 +1426,7 @@ gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName, bool gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1436,7 +1436,7 @@ gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(ff); + aOutput->AppendElement(FamilyAndGeneric(ff)); return true; } diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 37b62db94ca7..426c72cb5b1c 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -427,7 +427,7 @@ public: bool UseGDIFontTableAccess() { return mGDIFontTableAccess; } bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 987b08d19c88..5c0cd8f092b1 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -1893,7 +1893,7 @@ gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName, bool gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -1941,7 +1941,7 @@ gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, // Because the FcConfigSubstitute call is quite expensive, we cache the // actual font families found via this process. So check the cache first: NS_ConvertUTF16toUTF8 familyToFind(familyName); - AutoTArray cachedFamilies; + AutoTArray cachedFamilies; if (mFcSubstituteCache.Get(familyToFind, &cachedFamilies)) { if (cachedFamilies.IsEmpty()) { return false; @@ -2090,7 +2090,7 @@ gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, void gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { bool usePrefFontList = false; @@ -2147,7 +2147,10 @@ gfxFcPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, PrefFontList* prefFonts = FindGenericFamilies(genericToLookup, aLanguage); NS_ASSERTION(prefFonts, "null generic font list"); - aFamilyList.AppendElements(*prefFonts); + aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); + for (auto& f : *prefFonts) { + aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); + } } void @@ -2258,14 +2261,14 @@ gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric, FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric); if (mappedGeneric) { NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric)); - AutoTArray genericFamilies; + AutoTArray genericFamilies; if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName, &genericFamilies, FindFamiliesFlags(0))) { MOZ_ASSERT(genericFamilies.Length() == 1, "expected a single family"); - if (!prefFonts->Contains(genericFamilies[0])) { - prefFonts->AppendElement(genericFamilies[0]); + if (!prefFonts->Contains(genericFamilies[0].mFamily)) { + prefFonts->AppendElement(genericFamilies[0].mFamily); bool foundLang = !fcLang.IsEmpty() && PatternHasLang(font, ToFcChar8Ptr(fcLang.get())); diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 251990035dcd..63950d5e5ef1 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -305,7 +305,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; @@ -318,7 +318,7 @@ public: // override to use fontconfig lookup for generics void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) override; + nsTArray& aFamilyList) override; void ClearLangGroupPrefFonts() override; @@ -399,7 +399,7 @@ protected: // these pointers will be invalidated. InitFontList() flushes the cache // in this case. nsDataHashtable> mFcSubstituteCache; + nsTArray> mFcSubstituteCache; nsCOMPtr mCheckFontUpdatesTimer; nsCountedRef mLastConfig; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index e122e90d23c2..8eb7d160c91e 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -631,12 +631,17 @@ protected: }; struct gfxTextRange { - enum class MatchType : uint8_t { + enum class MatchType : uint16_t { + // The CSS generic that mapped to this font, if any. This field of + // the MatchType stores a FontFamilyType value as defined in the enum + // in gfxFontFamilyList.h. + kGenericMask = 0x00ff, + // Flags for recording the kind of font-matching that was used. // Note that multiple flags may be set on a single range. - kFontGroup = 0x01, - kPrefsFallback = 0x02, - kSystemFallback = 0x04 + kFontGroup = 0x0100, + kPrefsFallback = 0x0200, + kSystemFallback = 0x0400 }; gfxTextRange(uint32_t aStart, uint32_t aEnd, gfxFont* aFont, MatchType aMatchType, diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index c1246ed90240..8e975a2bc7cf 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -925,4 +925,29 @@ protected: }; }; +// Struct used in the gfxFontGroup font list to keep track of a font family +// together with the CSS generic (if any) that was mapped to it in this +// particular case (so it can be reported to the DevTools font inspector). +struct FamilyAndGeneric final { + FamilyAndGeneric() + : mFamily(nullptr) + , mGeneric(mozilla::FontFamilyType::eFamily_none) + { + } + FamilyAndGeneric(const FamilyAndGeneric& aOther) + : mFamily(aOther.mFamily) + , mGeneric(aOther.mGeneric) + { + } + explicit FamilyAndGeneric(gfxFontFamily* aFamily, + mozilla::FontFamilyType aGeneric = + mozilla::FontFamilyType::eFamily_none) + : mFamily(aFamily) + , mGeneric(aGeneric) + { + } + gfxFontFamily* mFamily; + mozilla::FontFamilyType mGeneric; +}; + #endif diff --git a/gfx/thebes/gfxFontFamilyList.h b/gfx/thebes/gfxFontFamilyList.h index ccfd3476edf9..e60e789f7903 100644 --- a/gfx/thebes/gfxFontFamilyList.h +++ b/gfx/thebes/gfxFontFamilyList.h @@ -23,7 +23,7 @@ namespace mozilla { * between unquoted and quoted names for serializaiton */ -enum FontFamilyType : uint32_t { +enum FontFamilyType : uint8_t { eFamily_none = 0, // used when finding generics // explicitly named font family (e.g. Helvetica) diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index aff93de8aac0..1b83d7f74dfb 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -882,7 +882,7 @@ gfxGDIFontList::MakePlatformFont(const nsAString& aFontName, bool gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -892,7 +892,7 @@ gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, gfxFontFamily *ff = mFontSubstitutes.GetWeak(keyName); if (ff) { - aOutput->AppendElement(ff); + aOutput->AppendElement(FamilyAndGeneric(ff)); return true; } diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 8d18a0c9d125..8530497dd19c 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -326,7 +326,7 @@ public: gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index ee220b8a80ab..281341bfdc5a 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -156,7 +156,7 @@ public: uint32_t aLength) override; bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index f42239e4b854..f7435257f377 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -1628,7 +1628,7 @@ static const char kSystemFont_system[] = "-apple-system"; bool gfxMacPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index faa30e86c11b..aebf33faeef8 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -751,7 +751,7 @@ gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily) bool gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) @@ -818,7 +818,7 @@ gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, } if (familyEntry) { - aOutput->AppendElement(familyEntry); + aOutput->AppendElement(FamilyAndGeneric(familyEntry)); return true; } @@ -1011,12 +1011,12 @@ gfxPlatformFontList::GetFontFamiliesFromGenericFamilies( gfxFontStyle style; style.language = aLangGroup; style.systemFont = false; - AutoTArray families; + AutoTArray families; FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0), &style); - for (gfxFontFamily* f : families) { - if (!aGenericFamilies->Contains(f)) { - aGenericFamilies->AppendElement(f); + for (const FamilyAndGeneric& f : families) { + if (!aGenericFamilies->Contains(f.mFamily)) { + aGenericFamilies->AppendElement(f.mFamily); } } } @@ -1055,7 +1055,7 @@ gfxPlatformFontList::GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, void gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // map lang ==> langGroup nsAtom* langGroup = GetLangGroup(aLanguage); @@ -1068,7 +1068,10 @@ gfxPlatformFontList::AddGenericFonts(mozilla::FontFamilyType aGenericType, GetPrefFontsLangGroup(aGenericType, prefLang); if (!prefFonts->IsEmpty()) { - aFamilyList.AppendElements(*prefFonts); + aFamilyList.SetCapacity(aFamilyList.Length() + prefFonts->Length()); + for (auto& f : *prefFonts) { + aFamilyList.AppendElement(FamilyAndGeneric(f.get(), aGenericType)); + } } } diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 34f427a75817..3b89bd94d84d 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -166,7 +166,7 @@ public: // Return true if any match was found and appended, false if none. virtual bool FindAndAddFamilies(const nsAString& aFamily, - nsTArray* aOutput, + nsTArray* aOutput, FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); @@ -263,7 +263,7 @@ public: virtual void AddGenericFonts(mozilla::FontFamilyType aGenericType, nsAtom* aLanguage, - nsTArray& aFamilyList); + nsTArray& aFamilyList); nsTArray>* GetPrefFontsLangGroup(mozilla::FontFamilyType aGenericType, @@ -305,6 +305,8 @@ public: bool AddWithLegacyFamilyName(const nsAString& aLegacyName, gfxFontEntry* aFontEntry); + static const char* GetGenericName(mozilla::FontFamilyType aGenericType); + protected: class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable { @@ -403,12 +405,13 @@ protected: gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { - AutoTArray families; + AutoTArray families; return FindAndAddFamilies(aFamily, &families, aFlags, aStyle, - aDevToCssSize) ? families[0] : nullptr; + aDevToCssSize) + ? families[0].mFamily : nullptr; } // Lookup family name in global family list without substitutions or @@ -488,8 +491,6 @@ protected: // helper function to map lang to lang group nsAtom* GetLangGroup(nsAtom* aLanguage); - static const char* GetGenericName(mozilla::FontFamilyType aGenericType); - // gfxFontInfoLoader overrides, used to load in font cmaps virtual void InitLoader() override; virtual bool LoadFontInfo() override; diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 67982992e82f..f00f9ace5afa 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1796,7 +1796,7 @@ void gfxFontGroup::BuildFontList() { // initialize fonts in the font family list - AutoTArray fonts; + AutoTArray fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); // lookup fonts in the fontlist @@ -1822,14 +1822,14 @@ gfxFontGroup::BuildFontList() } // build the fontlist from the specified families - for (gfxFontFamily* fontFamily : fonts) { - AddFamilyToFontList(fontFamily); + for (const auto& f : fonts) { + AddFamilyToFontList(f.mFamily, f.mGeneric); } } void gfxFontGroup::AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList) + nsTArray& aFamilyList) { // First, look up in the user font set... // If the fontSet matches the family, we must not look for a platform @@ -1853,7 +1853,8 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, } void -gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) +gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily, + FontFamilyType aGeneric) { NS_ASSERTION(aFamily, "trying to add a null font family to fontlist"); AutoTArray fontEntryList; @@ -1861,7 +1862,7 @@ gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily) // add these to the fontlist for (gfxFontEntry* fe : fontEntryList) { if (!HasFont(fe)) { - FamilyFace ff(aFamily, fe); + FamilyFace ff(aFamily, fe, aGeneric); if (fe->mIsUserFontContainer) { ff.CheckState(mSkipDrawing); } @@ -2064,7 +2065,7 @@ gfxFontGroup::GetDefaultFont() } gfxFont* -gfxFontGroup::GetFirstValidFont(uint32_t aCh) +gfxFontGroup::GetFirstValidFont(uint32_t aCh, FontFamilyType* aGeneric) { uint32_t count = mFonts.Length(); for (uint32_t i = 0; i < count; ++i) { @@ -2076,6 +2077,9 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh) // already have a font? gfxFont* font = ff.Font(); if (font) { + if (aGeneric) { + *aGeneric = ff.Generic(); + } return font; } @@ -2099,9 +2103,15 @@ gfxFontGroup::GetFirstValidFont(uint32_t aCh) font = GetFontAt(i, aCh); if (font) { + if (aGeneric) { + *aGeneric = mFonts[i].Generic(); + } return font; } } + if (aGeneric) { + *aGeneric = eFamily_none; + } return GetDefaultFont(); } @@ -2889,7 +2899,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* firstFont = GetFontAt(0, aCh); if (firstFont) { if (firstFont->HasCharacter(aCh)) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); return firstFont; } @@ -2904,7 +2915,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, font = FindFallbackFaceForChar(mFonts[0].Family(), aCh); } if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); return font; } } @@ -2954,6 +2966,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, gfxFont* font = ff.Font(); if (font) { if (font->HasCharacter(aCh)) { + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } continue; @@ -2982,7 +2996,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (pfe && pfe->HasCharacter(aCh)) { font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[i].Generic()); return font; } } @@ -2991,7 +3006,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, // build the font via GetFontAt font = GetFontAt(i, aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[i].Generic()); return font; } } @@ -3004,7 +3020,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, "should only do fallback once per font family"); font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } } else { @@ -3015,7 +3032,8 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, if (!fe->mIsUserFontContainer && !fe->IsUserFont()) { font = FindFallbackFaceForChar(ff.Family(), aCh); if (font) { - *aMatchType = gfxTextRange::MatchType::kFontGroup; + *aMatchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(ff.Generic()); return font; } } @@ -3084,11 +3102,13 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, // initialize prevFont to the group's primary font, so that this will be // used for string-initial control chars, etc rather than risk hitting font // fallback for these (bug 716229) - gfxFont *prevFont = GetFirstValidFont(); + FontFamilyType generic = eFamily_none; + gfxFont *prevFont = GetFirstValidFont(' ', &generic); // if we use the initial value of prevFont, we treat this as a match from // the font group; fixes bug 978313 - gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup; + gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(generic); for (uint32_t i = 0; i < aLength; i++) { @@ -3138,7 +3158,8 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, && !gfxFontUtils::IsJoinControl(ch) && !gfxFontUtils::IsJoinCauser(prevCh) && !gfxFontUtils::IsVarSelector(ch)))) { - matchType = gfxTextRange::MatchType::kFontGroup; + matchType = gfxTextRange::MatchType::kFontGroup | + gfxTextRange::MatchType(mFonts[0].Generic()); } else { font = FindFontForChar(ch, prevCh, nextCh, aRunScript, prevFont, &matchType); @@ -3146,9 +3167,9 @@ void gfxFontGroup::ComputeRanges(nsTArray& aRanges, #ifndef RELEASE_OR_BETA if (MOZ_UNLIKELY(mTextPerf)) { - if (matchType == gfxTextRange::MatchType::kPrefsFallback) { + if (matchType & gfxTextRange::MatchType::kPrefsFallback) { mTextPerf->current.fallbackPrefs++; - } else if (matchType == gfxTextRange::MatchType::kSystemFallback) { + } else if (matchType & gfxTextRange::MatchType::kSystemFallback) { mTextPerf->current.fallbackSystem++; } } diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index b55d25676373..ed2e1a0c93fb 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -864,8 +864,11 @@ public: virtual ~gfxFontGroup(); // Returns first valid font in the fontlist or default font. - // Initiates userfont loads if userfont not loaded - gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); + // Initiates userfont loads if userfont not loaded. + // aGeneric: if non-null, returns the CSS generic type that was mapped to + // this font + gfxFont* GetFirstValidFont(uint32_t aCh = 0x20, + mozilla::FontFamilyType* aGeneric = nullptr); // Returns the first font in the font-group that has an OpenType MATH table, // or null if no such font is available. The GetMathConstant methods may be @@ -1025,13 +1028,15 @@ protected: class FamilyFace { public: FamilyFace() : mFamily(nullptr), mFontEntry(nullptr), + mGeneric(mozilla::eFamily_none), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { } - FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont) - : mFamily(aFamily), mFontCreated(true), + FamilyFace(gfxFontFamily* aFamily, gfxFont* aFont, + mozilla::FontFamilyType aGeneric) + : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(true), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFont, "font pointer must not be null"); @@ -1042,8 +1047,9 @@ protected: NS_ADDREF(aFont); } - FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry) - : mFamily(aFamily), mFontCreated(false), + FamilyFace(gfxFontFamily* aFamily, gfxFontEntry* aFontEntry, + mozilla::FontFamilyType aGeneric) + : mFamily(aFamily), mGeneric(aGeneric), mFontCreated(false), mLoading(false), mInvalid(false), mCheckForFallbackFaces(false) { NS_ASSERTION(aFontEntry, "font entry pointer must not be null"); @@ -1056,6 +1062,7 @@ protected: FamilyFace(const FamilyFace& aOtherFamilyFace) : mFamily(aOtherFamilyFace.mFamily), + mGeneric(aOtherFamilyFace.mGeneric), mFontCreated(aOtherFamilyFace.mFontCreated), mLoading(aOtherFamilyFace.mLoading), mInvalid(aOtherFamilyFace.mInvalid), @@ -1088,6 +1095,7 @@ protected: } mFamily = aOther.mFamily; + mGeneric = aOther.mGeneric; mFontCreated = aOther.mFontCreated; mLoading = aOther.mLoading; mInvalid = aOther.mInvalid; @@ -1112,6 +1120,8 @@ protected: return mFontCreated ? mFont->GetFontEntry() : mFontEntry; } + mozilla::FontFamilyType Generic() const { return mGeneric; } + bool IsUserFontContainer() const { return FontEntry()->mIsUserFontContainer; } @@ -1148,6 +1158,7 @@ protected: gfxFont* MOZ_OWNING_REF mFont; gfxFontEntry* MOZ_OWNING_REF mFontEntry; }; + mozilla::FontFamilyType mGeneric; bool mFontCreated : 1; bool mLoading : 1; bool mInvalid : 1; @@ -1259,10 +1270,11 @@ protected: // lookup and add a font with a given name (i.e. *not* a generic!) void AddPlatformFont(const nsAString& aName, - nsTArray& aFamilyList); + nsTArray& aFamilyList); // do style selection and add entries to list - void AddFamilyToFontList(gfxFontFamily* aFamily); + void AddFamilyToFontList(gfxFontFamily* aFamily, + mozilla::FontFamilyType aGeneric); }; // A "missing font recorder" is to be used during text-run creation to keep diff --git a/layout/inspector/InspectorFontFace.cpp b/layout/inspector/InspectorFontFace.cpp index ea099428f8e9..1d28177ebb70 100644 --- a/layout/inspector/InspectorFontFace.cpp +++ b/layout/inspector/InspectorFontFace.cpp @@ -6,6 +6,7 @@ #include "InspectorFontFace.h" +#include "gfxPlatformFontList.h" #include "gfxTextRun.h" #include "gfxUserFontSet.h" #include "nsFontFaceLoader.h" @@ -55,6 +56,19 @@ InspectorFontFace::GetCSSFamilyName(nsAString& aCSSFamilyName) aCSSFamilyName = mFontEntry->FamilyName(); } +void +InspectorFontFace::GetCSSGeneric(nsAString& aName) +{ + auto genericType = + FontFamilyType(mMatchType & gfxTextRange::MatchType::kGenericMask); + if (genericType >= FontFamilyType::eFamily_generic_first && + genericType <= FontFamilyType::eFamily_generic_last) { + aName.AssignASCII(gfxPlatformFontList::GetGenericName(genericType)); + } else { + aName.Truncate(0); + } +} + ServoFontFaceRule* InspectorFontFace::GetRule() { diff --git a/layout/inspector/InspectorFontFace.h b/layout/inspector/InspectorFontFace.h index 501cf6bb86f2..a123bbcbb9de 100644 --- a/layout/inspector/InspectorFontFace.h +++ b/layout/inspector/InspectorFontFace.h @@ -56,6 +56,7 @@ public: bool FromSystemFallback(); void GetName(nsAString& aName); void GetCSSFamilyName(nsAString& aCSSFamilyName); + void GetCSSGeneric(nsAString& aGeneric); ServoFontFaceRule* GetRule(); int32_t SrcIndex(); void GetURI(nsAString& aURI); diff --git a/layout/inspector/tests/chrome/chrome.ini b/layout/inspector/tests/chrome/chrome.ini index 3d7fc5affcf7..a8866410d9ba 100644 --- a/layout/inspector/tests/chrome/chrome.ini +++ b/layout/inspector/tests/chrome/chrome.ini @@ -28,3 +28,4 @@ support-files = skip-if = (os == 'win' || os == 'linux' || os == 'mac') # bug 1433438, bug 1456855, bug 1456856 support-files = test_fontVariationsAPI.css +[test_fontFaceGeneric.xul] diff --git a/layout/inspector/tests/chrome/test_fontFaceGeneric.xul b/layout/inspector/tests/chrome/test_fontFaceGeneric.xul new file mode 100644 index 000000000000..6c97f7f28c76 --- /dev/null +++ b/layout/inspector/tests/chrome/test_fontFaceGeneric.xul @@ -0,0 +1,62 @@ + + + + + + + + +
test one
+
test two
+
test three
+ + +
diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index 193f2c1d5961..6179fbe40424 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -36,7 +36,7 @@ struct nsFont; namespace mozilla { class FontFamilyList; struct FontFamilyName; - enum FontFamilyType : uint32_t; + enum FontFamilyType : uint8_t; class SharedFontList; enum class CSSPseudoElementType : uint8_t; struct Keyframe; From 67537a721bce008fb1547254fa123d2324c4428b Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Thu, 10 May 2018 10:41:13 +0100 Subject: [PATCH 056/116] Bug 1270217 - Change the default MACOS_DEPLOYMENT_TARGET value to 10.9. r=froydnj --HG-- extra : rebase_source : bb180a82c87bb49c688dbcb2f8da6756e6c54224 --- build/gyp.mozbuild | 4 ++-- build/moz.configure/toolchain.configure | 2 +- old-configure.in | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/gyp.mozbuild b/build/gyp.mozbuild index 83b85d43baf0..a78289b0c448 100644 --- a/build/gyp.mozbuild +++ b/build/gyp.mozbuild @@ -16,8 +16,8 @@ gyp_vars.update({ 'build_with_mozilla': 1, 'build_with_chromium': 0, # 10.9 once we move to TC cross-compiles - bug 1270217 - 'mac_sdk_min': '10.7', - 'mac_deployment_target': '10.7', + 'mac_sdk_min': '10.9', + 'mac_deployment_target': '10.9', 'use_official_google_api_keys': 0, 'have_clock_monotonic': 1 if CONFIG['HAVE_CLOCK_MONOTONIC'] else 0, 'have_ethtool_cmd_speed_hi': 1 if CONFIG['MOZ_WEBRTC_HAVE_ETHTOOL_SPEED_HI'] else 0, diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure index db48969ae44c..126a15509502 100755 --- a/build/moz.configure/toolchain.configure +++ b/build/moz.configure/toolchain.configure @@ -144,7 +144,7 @@ include('android-ndk.configure', when=compiling_android) # This needs to happen before any compilation test is done. option('--enable-macos-target', env='MACOSX_DEPLOYMENT_TARGET', nargs=1, - default='10.7', help='Set the minimum MacOS version needed at runtime') + default='10.9', help='Set the minimum MacOS version needed at runtime') @depends('--enable-macos-target', target) diff --git a/old-configure.in b/old-configure.in index 529a0793de0d..3c26d5045fee 100644 --- a/old-configure.in +++ b/old-configure.in @@ -2380,7 +2380,7 @@ if test -n "$MOZ_APPLEMEDIA"; then LDFLAGS="$LDFLAGS -framework AudioToolbox" dnl Verify CoreMedia is available. AC_CHECK_HEADER([CoreMedia/CoreMedia.h], [], - [AC_MSG_ERROR([MacOS X 10.7 SDK or later is required])]) + [AC_MSG_ERROR([MacOS X 10.9 SDK or later is required])]) fi fi # COMPILE_ENVIRONMENT From 50e6372cf9102928902e9a211ce19b7d5e28b123 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 1 Jun 2018 13:08:57 -0400 Subject: [PATCH 057/116] Bug 1464094 - print font variations as paths for PDF/PS output. r=jfkthame MozReview-Commit-ID: 3sPKD4pNwdy --- gfx/2d/2D.h | 2 + gfx/2d/DrawTargetCairo.cpp | 26 +++- gfx/2d/NativeFontResourceFontconfig.cpp | 17 ++- gfx/2d/NativeFontResourceFontconfig.h | 7 +- gfx/2d/ScaledFontFontconfig.cpp | 173 ++++++++++++++++++++++-- gfx/2d/ScaledFontFontconfig.h | 10 +- gfx/thebes/gfxFcPlatformFontList.cpp | 30 +++- gfx/thebes/gfxFcPlatformFontList.h | 3 +- gfx/thebes/gfxPrefs.h | 2 + modules/libpref/init/all.js | 5 + 10 files changed, 253 insertions(+), 22 deletions(-) diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 36cf914ec4da..87a0f88eeae7 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -881,6 +881,8 @@ public: virtual bool CanSerialize() { return false; } + virtual bool HasVariationSettings() { return false; } + void AddUserData(UserDataKey *key, void *userData, void (*destroy)(void*)) { mUserData.Add(key, userData, destroy); } diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 2c1dd06c2184..ab265866da45 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -15,6 +15,7 @@ #include "mozilla/Scoped.h" #include "mozilla/UniquePtr.h" #include "mozilla/Vector.h" +#include "gfxPrefs.h" #include "cairo.h" #include "cairo-tee.h" @@ -1348,6 +1349,19 @@ DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA) #endif } +static bool +SupportsVariationSettings(cairo_surface_t* surface) +{ + switch (cairo_surface_get_type(surface)) + { + case CAIRO_SURFACE_TYPE_PDF: + case CAIRO_SURFACE_TYPE_PS: + return false; + default: + return true; + } +} + void DrawTargetCairo::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, @@ -1403,7 +1417,17 @@ DrawTargetCairo::FillGlyphs(ScaledFont *aFont, glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y; } - cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs); + if (!SupportsVariationSettings(mSurface) && + aFont->HasVariationSettings() && + gfxPrefs::PrintFontVariationsAsPaths()) { + cairo_set_fill_rule(mContext, CAIRO_FILL_RULE_WINDING); + cairo_new_path(mContext); + cairo_glyph_path(mContext, &glyphs[0], aBuffer.mNumGlyphs); + cairo_set_operator(mContext, CAIRO_OPERATOR_OVER); + cairo_fill(mContext); + } else { + cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs); + } if (cairo_surface_status(cairo_get_group_target(mContext))) { gfxDebug() << "Ending FillGlyphs with a bad surface " << cairo_surface_status(cairo_get_group_target(mContext)); diff --git a/gfx/2d/NativeFontResourceFontconfig.cpp b/gfx/2d/NativeFontResourceFontconfig.cpp index 7137079479d2..ce4e55544b39 100644 --- a/gfx/2d/NativeFontResourceFontconfig.cpp +++ b/gfx/2d/NativeFontResourceFontconfig.cpp @@ -12,9 +12,12 @@ namespace mozilla { namespace gfx { -NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr&& aFontData, FT_Face aFace) - : mFontData(std::move(aFontData)), - mFace(aFace) +NativeFontResourceFontconfig::NativeFontResourceFontconfig(UniquePtr&& aFontData, + uint32_t aDataLength, + FT_Face aFace) + : mFontData(std::move(aFontData)) + , mDataLength(aDataLength) + , mFace(aFace) { } @@ -48,7 +51,7 @@ NativeFontResourceFontconfig::Create(uint8_t *aFontData, uint32_t aDataLength, F } RefPtr resource = - new NativeFontResourceFontconfig(std::move(fontData), face); + new NativeFontResourceFontconfig(std::move(fontData), aDataLength, face); return resource.forget(); } @@ -60,5 +63,11 @@ NativeFontResourceFontconfig::CreateUnscaledFont(uint32_t aIndex, return unscaledFont.forget(); } +FT_Face +NativeFontResourceFontconfig::CloneFace() +{ + return Factory::NewFTFaceFromData(mFace->glyph->library, mFontData.get(), mDataLength, 0); +} + } // gfx } // mozilla diff --git a/gfx/2d/NativeFontResourceFontconfig.h b/gfx/2d/NativeFontResourceFontconfig.h index 1d4df0c46476..a4f3e8c7277e 100644 --- a/gfx/2d/NativeFontResourceFontconfig.h +++ b/gfx/2d/NativeFontResourceFontconfig.h @@ -29,10 +29,15 @@ public: ~NativeFontResourceFontconfig(); + FT_Face CloneFace(); + private: - NativeFontResourceFontconfig(UniquePtr&& aFontData, FT_Face aFace); + NativeFontResourceFontconfig(UniquePtr&& aFontData, + uint32_t aDataLength, + FT_Face aFace); UniquePtr mFontData; + uint32_t mDataLength; FT_Face mFace; }; diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index 3bc02881c4e9..c51a88d19c4e 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -6,7 +6,9 @@ #include "ScaledFontFontconfig.h" #include "UnscaledFontFreeType.h" +#include "NativeFontResourceFontconfig.h" #include "Logging.h" +#include "StackArray.h" #include "mozilla/webrender/WebRenderTypes.h" #ifdef USE_SKIA @@ -14,6 +16,9 @@ #endif #include +#include + +#include FT_MULTIPLE_MASTERS_H namespace mozilla { namespace gfx { @@ -224,12 +229,67 @@ ScaledFontFontconfig::InstanceData::SetupFontMatrix(cairo_matrix_t* aFontMatrix) cairo_matrix_init(aFontMatrix, mScale, 0, mSkew, mScale, 0, 0); } +void +ScaledFontFontconfig::GetVariationSettings(std::vector* aVariations) +{ + aVariations->clear(); + + typedef FT_Error (*GetVarFunc)(FT_Face, FT_MM_Var**); + typedef FT_Error (*DoneVarFunc)(FT_Library, FT_MM_Var*); + typedef FT_Error (*GetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*); + static GetVarFunc getVar; + static DoneVarFunc doneVar; + static GetVarDesignCoordsFunc getCoords; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + getVar = (GetVarFunc)dlsym(RTLD_DEFAULT, "FT_Get_MM_Var"); + doneVar = (DoneVarFunc)dlsym(RTLD_DEFAULT, "FT_Done_MM_Var"); + getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Get_Var_Design_Coordinates"); + } + + cairo_scaled_font_t* sf = GetCairoScaledFont(); + FT_Face face = cairo_ft_scaled_font_lock_face(sf); + if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var* mmVar; + if ((*getVar)(face, &mmVar) == FT_Err_Ok) { + aVariations->reserve(mmVar->num_axis); + StackArray coords(mmVar->num_axis); + if ((*getCoords)(face, mmVar->num_axis, coords.data()) == FT_Err_Ok) { + bool changed = false; + for (uint32_t i = 0; i < mmVar->num_axis; i++) { + if (coords[i] != mmVar->axis[i].def) { + changed = true; + } + aVariations->push_back(FontVariation{uint32_t(mmVar->axis[i].tag), + float(coords[i] / 65536.0)}); + } + if (!changed) { + aVariations->clear(); + } + } + if (doneVar) { + (*doneVar)(face->glyph->library, mmVar); + } else { + free(mmVar); + } + } + } + cairo_ft_scaled_font_unlock_face(sf); +} + bool ScaledFontFontconfig::GetFontInstanceData(FontInstanceDataOutput aCb, void* aBaton) { InstanceData instance(GetCairoScaledFont(), mPattern); - aCb(reinterpret_cast(&instance), sizeof(instance), nullptr, 0, aBaton); + std::vector variations; + if (HasVariationSettings()) { + GetVariationSettings(&variations); + } + + aCb(reinterpret_cast(&instance), sizeof(instance), + variations.data(), variations.size(), aBaton); return true; } @@ -348,6 +408,11 @@ ScaledFontFontconfig::GetWRFontInstanceOptions(Maybe* a *aOutOptions = Some(options); *aOutPlatformOptions = Some(platformOptions); + + if (HasVariationSettings()) { + GetVariationSettings(aOutVariations); + } + return true; } @@ -364,8 +429,12 @@ UnscaledFontFontconfig::CreateScaledFont(Float aGlyphSize, } const ScaledFontFontconfig::InstanceData *instanceData = reinterpret_cast(aInstanceData); - return ScaledFontFontconfig::CreateFromInstanceData(*instanceData, this, aGlyphSize, - mNativeFontResource.get()); + RefPtr scaledFont = + ScaledFontFontconfig::CreateFromInstanceData(*instanceData, this, aGlyphSize, + aVariations, aNumVariations, + static_cast( + mNativeFontResource.get())); + return scaledFont.forget(); } static cairo_user_data_key_t sNativeFontResourceKey; @@ -376,20 +445,37 @@ ReleaseNativeFontResource(void* aData) static_cast(aData)->Release(); } +static cairo_user_data_key_t sFaceKey; + +static void +ReleaseFace(void* aData) +{ + Factory::ReleaseFTFace(static_cast(aData)); +} + already_AddRefed ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, UnscaledFontFontconfig* aUnscaledFont, Float aSize, - NativeFontResource* aNativeFontResource) + const FontVariation* aVariations, + uint32_t aNumVariations, + NativeFontResourceFontconfig* aNativeFontResource) { FcPattern* pattern = FcPatternCreate(); if (!pattern) { - gfxWarning() << "Failing initializing Fontconfig pattern for scaled font"; + gfxWarning() << "Failed initializing Fontconfig pattern for scaled font"; return nullptr; } FT_Face face = aUnscaledFont->GetFace(); + FT_Face varFace = nullptr; if (face) { - FcPatternAddFTFace(pattern, FC_FT_FACE, face); + if (aNativeFontResource && aNumVariations > 0) { + varFace = aNativeFontResource->CloneFace(); + if (!varFace) { + gfxWarning() << "Failed cloning face for variations"; + } + } + FcPatternAddFTFace(pattern, FC_FT_FACE, varFace ? varFace : face); } else { FcPatternAddString(pattern, FC_FILE, reinterpret_cast(aUnscaledFont->GetFile())); FcPatternAddInteger(pattern, FC_INDEX, aUnscaledFont->GetIndex()); @@ -397,10 +483,18 @@ ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aSize); aInstanceData.SetupPattern(pattern); - cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern, nullptr, 0); + StackArray coords(aNumVariations); + for (uint32_t i = 0; i < aNumVariations; i++) { + coords[i] = std::round(aVariations[i].mValue * 65536.0); + } + + cairo_font_face_t* font = cairo_ft_font_face_create_for_pattern(pattern, coords.data(), aNumVariations); if (cairo_font_face_status(font) != CAIRO_STATUS_SUCCESS) { gfxWarning() << "Failed creating Cairo font face for Fontconfig pattern"; FcPatternDestroy(pattern); + if (varFace) { + Factory::ReleaseFTFace(varFace); + } return nullptr; } @@ -414,13 +508,28 @@ ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, // to prevent races if multiple threads are thus sharing the same Cairo face. FT_Library library = face ? face->glyph->library : Factory::GetFTLibrary(); Factory::LockFTLibrary(library); - cairo_status_t err = cairo_font_face_set_user_data(font, - &sNativeFontResourceKey, - aNativeFontResource, - ReleaseNativeFontResource); + cairo_status_t err = CAIRO_STATUS_SUCCESS; + bool cleanupFace = false; + if (varFace) { + err = cairo_font_face_set_user_data(font, + &sFaceKey, + varFace, + ReleaseFace); + } + if (err != CAIRO_STATUS_SUCCESS) { + cleanupFace = true; + } else { + err = cairo_font_face_set_user_data(font, + &sNativeFontResourceKey, + aNativeFontResource, + ReleaseNativeFontResource); + } Factory::UnlockFTLibrary(library); if (err != CAIRO_STATUS_SUCCESS) { gfxWarning() << "Failed binding NativeFontResource to Cairo font face"; + if (varFace && cleanupFace) { + Factory::ReleaseFTFace(varFace); + } aNativeFontResource->Release(); cairo_font_face_destroy(font); FcPatternDestroy(pattern); @@ -455,9 +564,51 @@ ScaledFontFontconfig::CreateFromInstanceData(const InstanceData& aInstanceData, cairo_scaled_font_destroy(cairoScaledFont); FcPatternDestroy(pattern); + // Only apply variations if we have an explicitly cloned face. Otherwise, + // if the pattern holds the pathname, Cairo will handle setting of variations. + if (varFace) { + scaledFont->ApplyVariations(aVariations, aNumVariations); + } + return scaledFont.forget(); } +void +ScaledFontFontconfig::ApplyVariations(const FontVariation* aVariations, + uint32_t aNumVariations) +{ + typedef FT_Error (*SetVarDesignCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*); + static SetVarDesignCoordsFunc setCoords; + static bool firstTime = true; + if (firstTime) { + firstTime = false; + setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates"); + } + + cairo_scaled_font_t* sf = GetCairoScaledFont(); + FT_Face face = cairo_ft_scaled_font_lock_face(sf); + if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + StackArray coords(aNumVariations); + for (uint32_t i = 0; i < aNumVariations; i++) { + coords[i] = std::round(aVariations[i].mValue * 65536.0f); + } + if ((*setCoords)(face, aNumVariations, coords.data()) != FT_Err_Ok) { + // ignore the problem? + } + } + cairo_ft_scaled_font_unlock_face(sf); +} + +bool +ScaledFontFontconfig::HasVariationSettings() +{ + // Check if the FT face has been cloned. + FT_Face face = nullptr; + return FcPatternGetFTFace(mPattern, FC_FT_FACE, 0, &face) == FcResultMatch && + face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS && + face != static_cast(mUnscaledFont.get())->GetFace(); +} + already_AddRefed UnscaledFontFontconfig::CreateFromFontDescriptor(const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) { diff --git a/gfx/2d/ScaledFontFontconfig.h b/gfx/2d/ScaledFontFontconfig.h index ec618dd3e1b5..052ef2fa37e7 100644 --- a/gfx/2d/ScaledFontFontconfig.h +++ b/gfx/2d/ScaledFontFontconfig.h @@ -39,10 +39,16 @@ public: Maybe* aOutPlatformOptions, std::vector* aOutVariations) override; + void ApplyVariations(const FontVariation* aVariations, uint32_t aNumVariations); + + bool HasVariationSettings() override; + private: friend class NativeFontResourceFontconfig; friend class UnscaledFontFontconfig; + void GetVariationSettings(std::vector* aVariations); + struct InstanceData { enum { @@ -72,7 +78,9 @@ private: CreateFromInstanceData(const InstanceData& aInstanceData, UnscaledFontFontconfig* aUnscaledFont, Float aSize, - NativeFontResource* aNativeFontResource = nullptr); + const FontVariation* aVariations, + uint32_t aNumVariations, + NativeFontResourceFontconfig* aNativeFontResource = nullptr); FcPattern* mPattern; }; diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 5c0cd8f092b1..4b9892eb88f7 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -749,10 +749,19 @@ ReleaseFTUserFontData(void* aData) static_cast(aData)->Release(); } +static cairo_user_data_key_t sFcFontlistFTFaceKey; + +static void +ReleaseFTFace(void* aData) +{ + Factory::ReleaseFTFace(static_cast(aData)); +} + cairo_scaled_font_t* gfxFontconfigFontEntry::CreateScaledFont(FcPattern* aRenderPattern, gfxFloat aAdjustedSize, - const gfxFontStyle *aStyle) + const gfxFontStyle *aStyle, + FT_Face aFTFace) { if (aStyle->NeedsSyntheticBold(this)) { FcPatternAddBool(aRenderPattern, FC_EMBOLDEN, FcTrue); @@ -784,9 +793,21 @@ gfxFontconfigFontEntry::CreateScaledFont(FcPattern* aRenderPattern, coords.Elements(), coords.Length()); + if (aFTFace) { + if (cairo_font_face_set_user_data(face, + &sFcFontlistFTFaceKey, + aFTFace, + ReleaseFTFace) != CAIRO_STATUS_SUCCESS) { + NS_WARNING("Failed binding FT_Face to Cairo font face"); + cairo_font_face_destroy(face); + Factory::ReleaseFTFace(aFTFace); + return nullptr; + } + } + if (mFontData) { // for data fonts, add the face/data pointer to the cairo font face - // so that it gets deleted whenever cairo decides + // so that it ges deleted whenever cairo decides NS_ASSERTION(mFTFace, "FT_Face is null when setting user data"); NS_ASSERTION(mUserFontData, "user font data is null when setting user data"); mUserFontData.get()->AddRef(); @@ -1009,11 +1030,14 @@ gfxFontconfigFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle) } if (!renderPattern) { NS_WARNING("Failed to prepare Fontconfig pattern for font instance"); + if (face != mFTFace) { + Factory::ReleaseFTFace(face); + } return nullptr; } cairo_scaled_font_t* scaledFont = - CreateScaledFont(renderPattern, size, aFontStyle); + CreateScaledFont(renderPattern, size, aFontStyle, face != mFTFace ? face : nullptr); const FcChar8* file = ToFcChar8Ptr(""); int index = 0; diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 63950d5e5ef1..35d7032e6fca 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -139,7 +139,8 @@ protected: cairo_scaled_font_t* CreateScaledFont(FcPattern* aRenderPattern, gfxFloat aAdjustedSize, - const gfxFontStyle *aStyle); + const gfxFontStyle *aStyle, + FT_Face aFTFace); // override to pull data from FTFace virtual nsresult diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index babd0aa9e04d..b0b1b8cb06a7 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -725,6 +725,8 @@ private: DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false); + DECL_GFX_PREF(Live, "print.font-variations-as-paths", PrintFontVariationsAsPaths, bool, true); + DECL_GFX_PREF(Once, "slider.snapMultiplier", SliderSnapMultiplier, int32_t, 0); DECL_GFX_PREF(Live, "test.events.async.enabled", TestEventsAsyncEnabled, bool, false); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index ed7d61779327..e2460c3344fe 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1138,6 +1138,11 @@ pref("print.print_via_parent", true); pref("print.print_via_parent", false); #endif +// Variation fonts can't always be embedded in certain output formats +// such as PDF. To work around this, draw the variation fonts using +// paths instead of using font embedding. +pref("print.font-variations-as-paths", true); + // Pref used by the spellchecker extension to control the // maximum number of misspelled words that will be underlined // in a document. From 8b3d9da4eb406347ba6a9039a4e9e62f482f0927 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 1 Jun 2018 13:12:55 -0400 Subject: [PATCH 058/116] Bug 1465585 - undo erroneous Move edit in Skia. r=me --- gfx/skia/skia/src/core/SkPath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/skia/skia/src/core/SkPath.cpp b/gfx/skia/skia/src/core/SkPath.cpp index 6454217b4e38..5048f3b24245 100644 --- a/gfx/skia/skia/src/core/SkPath.cpp +++ b/gfx/skia/skia/src/core/SkPath.cpp @@ -122,7 +122,7 @@ private: /* Stores the verbs and points as they are given to us, with exceptions: - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic - - we insert a std::move(0,0) if Line | Quad | Cubic is our first command + - we insert a Move(0,0) if Line | Quad | Cubic is our first command The iterator does more cleanup, especially if forceClose == true 1. If we encounter degenerate segments, remove them From 112114fba68a7f6815bddab22e45737fcc9078ff Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 1 Jun 2018 19:23:06 +0200 Subject: [PATCH 059/116] Bug 1465163 - Some UbiNode changes for same-compartment realms. r=fitzgen --- js/public/UbiNode.h | 33 ++++++++++++++++++++++-------- js/src/jsapi-tests/testUbiNode.cpp | 15 ++++++++++++++ js/src/vm/Debugger.cpp | 27 +++++++++++++++++++++++- js/src/vm/UbiNode.cpp | 29 +++++++++++++++++++++++--- 4 files changed, 92 insertions(+), 12 deletions(-) diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 3f9b85f3a278..9d0e74827f3b 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -603,6 +603,13 @@ class JS_PUBLIC_API(Base) { // nullptr is returned. virtual JSCompartment* compartment() const { return nullptr; } + // Return the realm for this node. Some ubi::Node referents are not + // associated with Realms, such as JSStrings (which are associated + // with Zones) or cross-compartment wrappers (which are associated with + // compartments). When the referent is not associated with a realm, + // nullptr is returned. + virtual JS::Realm* realm() const { return nullptr; } + // Return whether this node's referent's allocation stack was captured. virtual bool hasAllocationStack() const { return false; } @@ -776,6 +783,7 @@ class Node { const char16_t* typeName() const { return base()->typeName(); } JS::Zone* zone() const { return base()->zone(); } JSCompartment* compartment() const { return base()->compartment(); } + JS::Realm* realm() const { return base()->realm(); } const char* jsObjectClassName() const { return base()->jsObjectClassName(); } MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const { return base()->jsObjectConstructorName(cx, outName); @@ -981,7 +989,10 @@ class MOZ_STACK_CLASS JS_PUBLIC_API(RootList) { // Find all GC roots. MOZ_MUST_USE bool init(); - // Find only GC roots in the provided set of |JSCompartment|s. + // Find only GC roots in the provided set of |JSCompartment|s. Note: it's + // important to take a CompartmentSet and not a RealmSet: objects in + // same-compartment realms can reference each other directly, without going + // through CCWs, so if we used a RealmSet here we would miss edges. MOZ_MUST_USE bool init(CompartmentSet& debuggees); // Find only GC roots in the given Debugger object's set of debuggee // compartments. @@ -1027,14 +1038,16 @@ class JS_PUBLIC_API(TracerConcrete) : public Base { Referent& get() const { return *static_cast(ptr); } }; -// For JS::TraceChildren-based types that have a 'compartment' method. +// For JS::TraceChildren-based types that have 'realm' and 'compartment' +// methods. template -class JS_PUBLIC_API(TracerConcreteWithCompartment) : public TracerConcrete { +class JS_PUBLIC_API(TracerConcreteWithRealm) : public TracerConcrete { typedef TracerConcrete TracerBase; JSCompartment* compartment() const override; + JS::Realm* realm() const override; protected: - explicit TracerConcreteWithCompartment(Referent* ptr) : TracerBase(ptr) { } + explicit TracerConcreteWithRealm(Referent* ptr) : TracerBase(ptr) { } }; // Define specializations for some commonly-used public JSAPI types. @@ -1074,9 +1087,9 @@ class JS_PUBLIC_API(Concrete) : TracerConcrete { #endif template<> -class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment { +class JS_PUBLIC_API(Concrete) : TracerConcreteWithRealm { protected: - explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment(ptr) { } + explicit Concrete(JSScript *ptr) : TracerConcreteWithRealm(ptr) { } public: static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); } @@ -1091,15 +1104,18 @@ class JS_PUBLIC_API(Concrete) : TracerConcreteWithCompartment -class JS_PUBLIC_API(Concrete) : public TracerConcreteWithCompartment { +class JS_PUBLIC_API(Concrete) : public TracerConcrete { protected: - explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { } + explicit Concrete(JSObject* ptr) : TracerConcrete(ptr) { } public: static void construct(void* storage, JSObject* ptr) { new (storage) Concrete(ptr); } + JSCompartment* compartment() const override; + JS::Realm* realm() const override; + const char* jsObjectClassName() const override; MOZ_MUST_USE bool jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& outName) const override; @@ -1139,6 +1155,7 @@ class JS_PUBLIC_API(Concrete) : public Base { js::UniquePtr edges(JSContext* cx, bool wantNames) const override; JS::Zone* zone() const override; JSCompartment* compartment() const override; + JS::Realm* realm() const override; CoarseType coarseType() const final; explicit Concrete(void* ptr) : Base(ptr) { } diff --git a/js/src/jsapi-tests/testUbiNode.cpp b/js/src/jsapi-tests/testUbiNode.cpp index e414a2ba4315..d26059906e81 100644 --- a/js/src/jsapi-tests/testUbiNode.cpp +++ b/js/src/jsapi-tests/testUbiNode.cpp @@ -9,6 +9,7 @@ #include "js/UbiNodeShortestPaths.h" #include "jsapi-tests/tests.h" #include "util/Text.h" +#include "vm/JSCompartment.h" #include "vm/SavedFrame.h" using JS::RootedObject; @@ -118,6 +119,7 @@ BEGIN_TEST(test_ubiNodeCompartment) RootedObject global1(cx, JS::CurrentGlobalOrNull(cx)); CHECK(global1); CHECK(JS::ubi::Node(global1).compartment() == cx->compartment()); + CHECK(JS::ubi::Node(global1).realm() == cx->realm()); JS::RealmOptions globalOptions; RootedObject global2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, @@ -126,6 +128,8 @@ BEGIN_TEST(test_ubiNodeCompartment) CHECK(global1->compartment() != global2->compartment()); CHECK(JS::ubi::Node(global2).compartment() == global2->compartment()); CHECK(JS::ubi::Node(global2).compartment() != global1->compartment()); + CHECK(JS::ubi::Node(global2).realm() == global2->realm()); + CHECK(JS::ubi::Node(global2).realm() != global1->realm()); JS::CompileOptions options(cx); @@ -143,6 +147,17 @@ BEGIN_TEST(test_ubiNodeCompartment) CHECK(JS::ubi::Node(script1).compartment() == global1->compartment()); CHECK(JS::ubi::Node(script2).compartment() == global2->compartment()); + CHECK(JS::ubi::Node(script1).realm() == global1->realm()); + CHECK(JS::ubi::Node(script2).realm() == global2->realm()); + + // Now create a wrapper for global1 in global2's compartment. + RootedObject wrappedGlobal1(cx, global1); + CHECK(cx->compartment()->wrap(cx, &wrappedGlobal1)); + + // Cross-compartment wrappers have a compartment() but not a realm(). + CHECK(JS::ubi::Node(wrappedGlobal1).zone() == cx->zone()); + CHECK(JS::ubi::Node(wrappedGlobal1).compartment() == cx->compartment()); + CHECK(JS::ubi::Node(wrappedGlobal1).realm() == nullptr); } return true; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index eea6de9dce40..7f659fd9d83e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4781,6 +4781,9 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery /* The vector that we are accumulating results in. */ AutoObjectVector objects; + /* The set of debuggee compartments. */ + JS::CompartmentSet debuggeeCompartments; + /* * Parse the query object |query|, and prepare to match only the objects it * specifies. @@ -4815,6 +4818,18 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery if (!prepareQuery()) return false; + if (!debuggeeCompartments.init()) { + ReportOutOfMemory(cx); + return false; + } + + for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront()) { + if (!debuggeeCompartments.put(r.front()->compartment())) { + ReportOutOfMemory(cx); + return false; + } + } + { /* * We can't tolerate the GC moving things around while we're @@ -4866,11 +4881,21 @@ class MOZ_STACK_CLASS Debugger::ObjectQuery * node. */ JSCompartment* comp = referent.compartment(); - if (comp && !dbg->isDebuggeeUnbarriered(JS::GetRealmForCompartment(comp))) { + if (comp && !debuggeeCompartments.has(comp)) { traversal.abandonReferent(); return true; } + /* + * If the referent has an associated realm and it's not a debuggee + * realm, skip it. Don't abandonReferent() here like above: realms + * within a compartment can reference each other without going through + * cross-compartment wrappers. + */ + Realm* realm = referent.realm(); + if (realm && !dbg->isDebuggeeUnbarriered(realm)) + return true; + /* * If the referent is an object and matches our query's restrictions, * add it to the vector accumulating results. Skip objects that should diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 2a647bf95717..2ce60f721a1d 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -55,7 +55,7 @@ using JS::ubi::Node; using JS::ubi::EdgeVector; using JS::ubi::StackFrame; using JS::ubi::TracerConcrete; -using JS::ubi::TracerConcreteWithCompartment; +using JS::ubi::TracerConcreteWithRealm; struct CopyToBufferMatcher { @@ -161,6 +161,7 @@ CoarseType Concrete::coarseType() const { MOZ_CRASH("null ubi::Node") const char16_t* Concrete::typeName() const { MOZ_CRASH("null ubi::Node"); } JS::Zone* Concrete::zone() const { MOZ_CRASH("null ubi::Node"); } JSCompartment* Concrete::compartment() const { MOZ_CRASH("null ubi::Node"); } +JS::Realm* Concrete::realm() const { MOZ_CRASH("null ubi::Node"); } UniquePtr Concrete::edges(JSContext*, bool) const { @@ -357,12 +358,20 @@ template UniquePtr TracerConcrete::edges(JSContext* cx, boo template JSCompartment* -TracerConcreteWithCompartment::compartment() const +TracerConcreteWithRealm::compartment() const { return TracerBase::get().compartment(); } -template JSCompartment* TracerConcreteWithCompartment::compartment() const; +template +Realm* +TracerConcreteWithRealm::realm() const +{ + return TracerBase::get().realm(); +} + +template Realm* TracerConcreteWithRealm::realm() const; +template JSCompartment* TracerConcreteWithRealm::compartment() const; bool Concrete::hasAllocationStack() const @@ -407,6 +416,20 @@ Concrete::jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& o return true; } +JSCompartment* +Concrete::compartment() const +{ + return Concrete::get().compartment(); +} + +Realm* +Concrete::realm() const +{ + // Cross-compartment wrappers are shared by all realms in the compartment, + // so we return nullptr in that case. + return JS::GetObjectRealmOrNull(&Concrete::get()); +} + const char16_t Concrete::concreteTypeName[] = u"JS::Symbol"; #ifdef ENABLE_BIGINT const char16_t Concrete::concreteTypeName[] = u"JS::BigInt"; From 12cafc4a7de95ef50f9caab83274de308dcced0c Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Fri, 1 Jun 2018 19:23:14 +0200 Subject: [PATCH 060/116] Bug 1465002 part 2 - Don't skip wasm frames in GetScriptedCallerActivationRealmFast. r=luke --- js/src/jsapi.cpp | 21 ++++++++++++++------- js/src/vm/Stack.cpp | 22 ++++++++++++++++++++++ js/src/vm/Stack.h | 6 ++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d1e5be73d732..88ef5549b03a 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -7574,19 +7574,26 @@ GetScriptedCallerActivationRealmFast(JSContext* cx, Activation** activation, Rea } if (activationIter->isJit()) { - for (OnlyJSJitFrameIter iter(activationIter); !iter.done(); ++iter) { - if (!iter.frame().isScripted()) - continue; - if (!iter.frame().script()->selfHosted()) { - *activation = activationIter.activation(); - *realm = iter.frame().script()->realm(); + jit::JitActivation* act = activationIter->asJit(); + JitFrameIter iter(act); + while (true) { + iter.skipNonScriptedJSFrames(); + if (iter.done()) + break; + + if (!iter.isSelfHostedIgnoringInlining()) { + *activation = act; + *realm = iter.realm(); return true; } - if (iter.frame().isIonScripted()) { + + if (iter.isJSJit() && iter.asJSJit().isIonScripted()) { // Ion might have inlined non-self-hosted scripts in this // self-hosted script. return false; } + + ++iter; } } else if (activationIter->isInterpreter()) { InterpreterActivation* act = activationIter->asInterpreter(); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index a674fa9d8c63..5dcb55ed81d9 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -521,6 +521,28 @@ JitFrameIter::skipNonScriptedJSFrames() } } +bool +JitFrameIter::isSelfHostedIgnoringInlining() const +{ + MOZ_ASSERT(!done()); + + if (isWasm()) + return false; + + return asJSJit().script()->selfHosted(); +} + +JS::Realm* +JitFrameIter::realm() const +{ + MOZ_ASSERT(!done()); + + if (isWasm()) + return asWasm().instance()->realm(); + + return asJSJit().script()->realm(); +} + bool JitFrameIter::done() const { diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 138e93e233f0..735dc51fe312 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1950,8 +1950,14 @@ class JitFrameIter bool done() const; void operator++(); + JS::Realm* realm() const; + // Operations which have an effect only on JIT frames. void skipNonScriptedJSFrames(); + + // Returns true iff this is a JIT frame with a self-hosted script. Note: be + // careful, JitFrameIter does not consider functions inlined by Ion. + bool isSelfHostedIgnoringInlining() const; }; // A JitFrameIter that skips all the non-JSJit frames, skipping interleaved From 6f4724874e614e4817f2c3c6856bba62c446d7be Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 10:56:57 -0700 Subject: [PATCH 061/116] Bug 1465587 Only hide the initial internal redirect to an InterceptedHttpChannel and not internal redirects initiated from IHC. r=mayhemer --- netwerk/protocol/http/HttpChannelParent.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 5ae22413f626..12e8a1146cb3 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1766,17 +1766,15 @@ HttpChannelParent::StartRedirect(uint32_t registrarId, // was not designed with this in mind and its not necessary to replace // the HttpChannelChild/Parent objects in this case. if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) { - nsCOMPtr newIntercepted = do_QueryInterface(newChannel); - if (newIntercepted) { -#ifdef DEBUG - // Note, InterceptedHttpChannel can also do an internal redirect - // for opaque response interception. This should not actually - // happen here in e10s mode. - nsCOMPtr oldIntercepted = + nsCOMPtr oldIntercepted = do_QueryInterface(static_cast(mChannel.get())); - MOZ_ASSERT(!oldIntercepted); -#endif + nsCOMPtr newIntercepted = do_QueryInterface(newChannel); + // We only want to hide the special internal redirect from nsHttpChannel + // to InterceptedHttpChannel. We want to allow through internal redirects + // initiated from the InterceptedHttpChannel even if they are to another + // InterceptedHttpChannel. + if (!oldIntercepted && newIntercepted) { // We need to move across the reserved and initial client information // to the new channel. Normally this would be handled by the child // ClientChannelHelper, but that is not notified of this redirect since From 015a7772c0c41c0213b1c37d412bb6b781e34e9f Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 10:56:58 -0700 Subject: [PATCH 062/116] Bug 1465580 Make HttpChannelParent get the channel status when its underlying channel is an InterceptedHttpChannel. r=mayhemer --- netwerk/protocol/http/HttpChannelParent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 12e8a1146cb3..a433f4a27b2f 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1413,10 +1413,12 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) Unused << chan->GetApplyConversion(&applyConversion); chan->SetApplyConversion(false); + nsresult channelStatus = NS_OK; + chan->GetStatus(&channelStatus); + // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset(). // It could be already released by nsHttpChannel at that time. nsCOMPtr cacheEntry; - nsresult channelStatus = NS_OK; uint32_t cacheKey = 0; nsAutoCString altDataType; @@ -1424,8 +1426,6 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) httpChannelImpl->GetCacheToken(getter_AddRefs(cacheEntry)); mCacheEntry = do_QueryInterface(cacheEntry); - httpChannelImpl->GetStatus(&channelStatus); - httpChannelImpl->GetCacheKey(&cacheKey); httpChannelImpl->GetAlternativeDataType(altDataType); From 5f56932b65ef44346c1965c522157808bbddfad9 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 1 Jun 2018 09:31:00 -0400 Subject: [PATCH 063/116] Bug 1466166 - Fix test code for bug 1464872 to work with GC zeal. r=sfink --- js/src/jit-test/tests/gc/bug-1464872.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jit-test/tests/gc/bug-1464872.js b/js/src/jit-test/tests/gc/bug-1464872.js index 433e4a1314ce..44fa40b45445 100644 --- a/js/src/jit-test/tests/gc/bug-1464872.js +++ b/js/src/jit-test/tests/gc/bug-1464872.js @@ -1,3 +1,5 @@ +gczeal(0); + var g = newGlobal(); var dbg = Debugger(g); dbg.onEnterFrame = function(frame) {}; From 3c98fb69aba6c57a22e97b802f4c41a148603a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Fri, 1 Jun 2018 01:10:11 -0700 Subject: [PATCH 064/116] Bug 1466050 - Skip a call to strlen in Number.prototype.toString when length was already computed. r=jandem --HG-- extra : rebase_source : 646bed23c8f23224abf401cca7d161b20a417672 --- js/src/jsnum.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 482d3cd3190d..3759f689a88a 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1326,6 +1326,7 @@ NumberToStringWithBase(JSContext* cx, double d, int base) ToCStringBuf cbuf; char* numStr; + size_t numStrLen; Realm* realm = cx->realm(); @@ -1346,9 +1347,9 @@ NumberToStringWithBase(JSContext* cx, double d, int base) if (JSFlatString* str = realm->dtoaCache.lookup(base, d)) return str; - size_t len; - numStr = Int32ToCString(&cbuf, i, &len, base); + numStr = Int32ToCString(&cbuf, i, &numStrLen, base); MOZ_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); + MOZ_ASSERT(numStrLen == strlen(numStr)); } else { if (JSFlatString* str = realm->dtoaCache.lookup(base, d)) return str; @@ -1362,9 +1363,11 @@ NumberToStringWithBase(JSContext* cx, double d, int base) !cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize); MOZ_ASSERT_IF(base != 10, cbuf.dbuf && cbuf.dbuf == numStr); + + numStrLen = strlen(numStr); } - JSFlatString* s = NewStringCopyZ(cx, numStr); + JSFlatString* s = NewStringCopyN(cx, numStr, numStrLen); if (!s) return nullptr; @@ -1460,10 +1463,6 @@ js::NumberValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb) cstrlen = strlen(cstr); } - /* - * Inflate to char16_t string. The input C-string characters are < 127, so - * even if char16_t units are UTF-8, all chars should map to one char16_t. - */ MOZ_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize); return sb.append(cstr, cstrlen); } From 237be9e2468eeab40ff33c7a01b158dfb44cbb45 Mon Sep 17 00:00:00 2001 From: Andreea Pavel Date: Thu, 31 May 2018 04:28:00 -0400 Subject: [PATCH 065/116] Bug 1465373 - Remove reference to old winxp in manifest file. r=jmaher --HG-- extra : amend_source : 67da1820e99848c108f24ec67dbb5755a708c205 --- dom/canvas/test/webgl-mochitest/mochitest.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/canvas/test/webgl-mochitest/mochitest.ini b/dom/canvas/test/webgl-mochitest/mochitest.ini index 2c323fa6c42f..1d2fe03b43e5 100644 --- a/dom/canvas/test/webgl-mochitest/mochitest.ini +++ b/dom/canvas/test/webgl-mochitest/mochitest.ini @@ -44,7 +44,7 @@ fail-if = (os == 'android') || (os == 'linux') || (os == 'mac') || (os == 'win') fail-if = (os == 'android') [ensure-exts/test_WEBGL_depth_texture.html] [ensure-exts/test_WEBGL_draw_buffers.html] -fail-if = (os == 'android') || (os == 'win' && os_version == '5.1') +fail-if = (os == 'android') [ensure-exts/test_common.html] @@ -68,7 +68,6 @@ support-files = ../captureStream_common.js [test_fb_param_crash.html] [test_hidden_alpha.html] [test_hidden_depth_stencil.html] -fail-if = (os == 'win' && os_version == '5.1') [test_implicit_color_buffer_float.html] [test_highp_fs.html] [test_no_arr_points.html] From 46e2311a36f04835608e2feff1a946bf06da0a8a Mon Sep 17 00:00:00 2001 From: Andreea Pavel Date: Thu, 31 May 2018 06:20:00 -0400 Subject: [PATCH 066/116] Bug 1465375 - Remove reference to old winxp in manifest file. r=jmaher --- netwerk/test/unit/xpcshell.ini | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 76c3da3e39d3..59c0b0494029 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -358,21 +358,15 @@ skip-if = os != "win" [test_websocket_offline.js] [test_be_conservative.js] # The local cert service used by this test is not currently shipped on Android -# Disabled on XP in bug 1190674 for intermittent failures -skip-if = os == "android" || (os == "win" && (os_version == "5.1" || os_version == "5.2")) -reason = bug 1190674 +skip-if = os == "android" firefox-appdir = browser [test_be_conservative_error_handling.js] # The local cert service used by this test is not currently shipped on Android -# Disabled on XP in bug 1190674 for intermittent failures -skip-if = os == "android" || (os == "win" && (os_version == "5.1" || os_version == "5.2")) -reason = bug 1190674 +skip-if = os == "android" firefox-appdir = browser [test_tls_server.js] # The local cert service used by this test is not currently shipped on Android -# Disabled on XP in bug 1190674 for intermittent failures -skip-if = os == "android" || (os == "win" && (os_version == "5.1" || os_version == "5.2")) -reason = bug 1190674 +skip-if = os == "android" firefox-appdir = browser [test_tls_server_multiple_clients.js] # The local cert service used by this test is not currently shipped on Android From ee8f3a1498384d43628f1378cfddd862b4f688d7 Mon Sep 17 00:00:00 2001 From: qiaopengcheng Date: Thu, 31 May 2018 18:33:00 -0400 Subject: [PATCH 067/116] Bug 1465770 - mips64: convertDoubleToInt32 cp1_fcsr error. r=dragan.mladjenovic --- js/src/jit/mips64/MacroAssembler-mips64.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 8eec6bac047e..bb45f12bb599 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -112,11 +112,12 @@ MacroAssemblerMIPS64Compat::convertDoubleToInt32(FloatRegister src, Register des ma_b(dest, Imm32(1), fail, Assembler::Equal); } - // Truncate double to int ; if result is inexact fail + // Truncate double to int ; if result is inexact or invalid fail. as_truncwd(ScratchFloat32Reg, src); as_cfc1(ScratchRegister, Assembler::FCSR); moveFromFloat32(ScratchFloat32Reg, dest); - ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseI, 1); + ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseI, 6); + as_andi(ScratchRegister, ScratchRegister, 0x11);//masking for Inexact and Invalid flag. ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual); } From 7d63d1ce7d552b5899cef6932e35dce5cc3c3a6e Mon Sep 17 00:00:00 2001 From: qiaopengcheng Date: Fri, 1 Jun 2018 02:58:00 -0400 Subject: [PATCH 068/116] Bug 1465770 - mips32: convertDoubleToInt32 cp1_fcsr error. r=dragan.mladjenovic --- js/src/jit/mips32/MacroAssembler-mips32.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index ef0a9136f4e3..7c1db99d988c 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -132,11 +132,16 @@ MacroAssemblerMIPSCompat::convertDoubleToInt32(FloatRegister src, Register dest, ma_b(dest, Imm32(0), fail, Assembler::Equal); } - // Truncate double to int ; if result is inexact fail + // Truncate double to int ; if result is inexact or invalid fail. as_truncwd(ScratchFloat32Reg, src); as_cfc1(ScratchRegister, Assembler::FCSR); moveFromFloat32(ScratchFloat32Reg, dest); - ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseI, 1); + ma_ext(ScratchRegister, ScratchRegister, Assembler::CauseI, 6); + // Here adding the masking andi instruction just for a precaution. + // For the instruction of trunc.*.*, the Floating Point Exceptions can be + // only Inexact, Invalid Operation, Unimplemented Operation. + // Leaving it maybe is also ok. + as_andi(ScratchRegister, ScratchRegister, 0x11); ma_b(ScratchRegister, Imm32(0), fail, Assembler::NotEqual); } From fa531b047708f5cd94be11f72ed0b6e8c1586221 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Wed, 23 May 2018 17:02:33 +0200 Subject: [PATCH 069/116] Bug 1319273 - Accessible: Make TextBounds return rect of whole frame if content is empty. r=surkov --- accessible/generic/HyperTextAccessible.cpp | 11 +++++++++++ .../tests/browser/bounds/browser_test_zoom_text.js | 14 +++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp index b3dca03453eb..2f20f070b349 100644 --- a/accessible/generic/HyperTextAccessible.cpp +++ b/accessible/generic/HyperTextAccessible.cpp @@ -1241,6 +1241,17 @@ HyperTextAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset, return nsIntRect(); } + if (CharacterCount() == 0) { + nsPresContext* presContext = mDoc->PresContext(); + // Empty content, use our own bound to at least get x,y coordinates + return GetFrame()->GetScreenRectInAppUnits(). + ToNearestPixels(presContext->AppUnitsPerDevPixel()); + } + + if (startOffset == endOffset) { + NS_ERROR("Wrong in offset"); + return nsIntRect(); + } int32_t childIdx = GetChildIndexAtOffset(startOffset); if (childIdx == -1) diff --git a/accessible/tests/browser/bounds/browser_test_zoom_text.js b/accessible/tests/browser/bounds/browser_test_zoom_text.js index 37ea5b1cf2fa..a508557acd53 100644 --- a/accessible/tests/browser/bounds/browser_test_zoom_text.js +++ b/accessible/tests/browser/bounds/browser_test_zoom_text.js @@ -19,10 +19,21 @@ async function runTests(browser, accDoc) { COORDTYPE_SCREEN_RELATIVE); } + async function testEmptyInputNode(id) { + var inputNode = findAccessibleChildByID(accDoc, id); + + var [x, y, width, height] = getBounds(inputNode); + testTextBounds(inputNode, 0, -1, [x, y, width, height], + COORDTYPE_SCREEN_RELATIVE); + testTextBounds(inputNode, 0, 0, [x, y, width, height], + COORDTYPE_SCREEN_RELATIVE); + } + loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR }); await testTextNode("p1"); await testTextNode("p2"); + await testEmptyInputNode("i1"); await ContentTask.spawn(browser, {}, () => { zoomDocument(document, 2.0); @@ -40,5 +51,6 @@ async function runTests(browser, accDoc) { */ addAccessibleTask(`

Tilimilitryamdiya

-

ل

`, runTests +

ل

+
`, runTests ); From 348f30caa7d2dc3adc9d8a83ddaf37ad77657853 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Thu, 31 May 2018 10:34:00 -0400 Subject: [PATCH 070/116] Bug 1463496 - Enable WebSpeech synthesis in Android. r=smaug --- dom/tests/mochitest/general/test_interfaces.js | 10 +++++----- mobile/android/app/mobile.js | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dom/tests/mochitest/general/test_interfaces.js b/dom/tests/mochitest/general/test_interfaces.js index 1f7300be887e..3abd54dc2971 100644 --- a/dom/tests/mochitest/general/test_interfaces.js +++ b/dom/tests/mochitest/general/test_interfaces.js @@ -877,15 +877,15 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! {name: "SourceBufferList", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisErrorEvent", insecureContext: true, android: false}, + {name: "SpeechSynthesisErrorEvent", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisEvent", insecureContext: true, android: false}, + {name: "SpeechSynthesisEvent", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesis", insecureContext: true, android: false}, + {name: "SpeechSynthesis", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisUtterance", insecureContext: true, android: false}, + {name: "SpeechSynthesisUtterance", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "SpeechSynthesisVoice", insecureContext: true, android: false}, + {name: "SpeechSynthesisVoice", insecureContext: true}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "SpecialPowers", insecureContext: true, xbl: false}, // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index bdcaffa9da7d..eaf94656f80a 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -567,6 +567,9 @@ pref("media.mediasource.enabled", true); pref("media.mediadrm-widevinecdm.visible", true); +// Enable WebSpeech speech synthesis +pref("media.webspeech.synth.enabled", true); + // optimize images memory usage pref("image.downscale-during-decode.enabled", true); From 3451aa80a51f0f182eb7882fa5a8b6be311f9f0b Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 1 Jun 2018 13:11:21 -0600 Subject: [PATCH 071/116] Bug 1411358 - Increase Android/debug xpcshell max-run-time; r=me,a=test-only Task run time for these tests is highly variable across chunks: Some run in only 30 minutes, while xpcshell-11 sometimes exceeds 90 minutes. Rather than waste resources on more chunks, I think increasing the max task run time is a reasonable way of avoiding intermittent task time-outs. --- taskcluster/ci/test/xpcshell.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/taskcluster/ci/test/xpcshell.yml b/taskcluster/ci/test/xpcshell.yml index f47458c0dee5..16210e8dd6f0 100644 --- a/taskcluster/ci/test/xpcshell.yml +++ b/taskcluster/ci/test/xpcshell.yml @@ -50,7 +50,10 @@ xpcshell: by-test-platform: android.*: xlarge default: default - max-run-time: 5400 + max-run-time: + by-test-platform: + android-4.3-arm7-api-16/debug: 7200 + default: 5400 e10s: false allow-software-gl-layers: false tier: From ff15f3c8285cfe557a9c0ab5fc17678c245d50bf Mon Sep 17 00:00:00 2001 From: Gurzau Raul Date: Fri, 1 Jun 2018 22:25:19 +0300 Subject: [PATCH 072/116] Backed out changeset f585271d250d (bug 1319273) for eslint failures on /gecko/accessible/tests/browser/bounds/browser_test_zoom_text.js on a CLOSED TREE --- accessible/generic/HyperTextAccessible.cpp | 11 ----------- .../tests/browser/bounds/browser_test_zoom_text.js | 14 +------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp index 2f20f070b349..b3dca03453eb 100644 --- a/accessible/generic/HyperTextAccessible.cpp +++ b/accessible/generic/HyperTextAccessible.cpp @@ -1241,17 +1241,6 @@ HyperTextAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset, return nsIntRect(); } - if (CharacterCount() == 0) { - nsPresContext* presContext = mDoc->PresContext(); - // Empty content, use our own bound to at least get x,y coordinates - return GetFrame()->GetScreenRectInAppUnits(). - ToNearestPixels(presContext->AppUnitsPerDevPixel()); - } - - if (startOffset == endOffset) { - NS_ERROR("Wrong in offset"); - return nsIntRect(); - } int32_t childIdx = GetChildIndexAtOffset(startOffset); if (childIdx == -1) diff --git a/accessible/tests/browser/bounds/browser_test_zoom_text.js b/accessible/tests/browser/bounds/browser_test_zoom_text.js index a508557acd53..37ea5b1cf2fa 100644 --- a/accessible/tests/browser/bounds/browser_test_zoom_text.js +++ b/accessible/tests/browser/bounds/browser_test_zoom_text.js @@ -19,21 +19,10 @@ async function runTests(browser, accDoc) { COORDTYPE_SCREEN_RELATIVE); } - async function testEmptyInputNode(id) { - var inputNode = findAccessibleChildByID(accDoc, id); - - var [x, y, width, height] = getBounds(inputNode); - testTextBounds(inputNode, 0, -1, [x, y, width, height], - COORDTYPE_SCREEN_RELATIVE); - testTextBounds(inputNode, 0, 0, [x, y, width, height], - COORDTYPE_SCREEN_RELATIVE); - } - loadFrameScripts(browser, { name: "layout.js", dir: MOCHITESTS_DIR }); await testTextNode("p1"); await testTextNode("p2"); - await testEmptyInputNode("i1"); await ContentTask.spawn(browser, {}, () => { zoomDocument(document, 2.0); @@ -51,6 +40,5 @@ async function runTests(browser, accDoc) { */ addAccessibleTask(`

Tilimilitryamdiya

-

ل

-
`, runTests +

ل

`, runTests ); From 6069a3aae983e991d67c2da3d2d40e66b33cc791 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 1 Jun 2018 15:32:33 -0400 Subject: [PATCH 073/116] Bug 1464094 - follow-up - check that dlsym succeeded. r=me MozReview-Commit-ID: L6jOU6C9CHS --- gfx/2d/ScaledFontFontconfig.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index c51a88d19c4e..04d4e16ea30d 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -248,6 +248,10 @@ ScaledFontFontconfig::GetVariationSettings(std::vector* aVariatio getCoords = (GetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Get_Var_Design_Coordinates"); } + if (!getVar || !getCoords) { + return; + } + cairo_scaled_font_t* sf = GetCairoScaledFont(); FT_Face face = cairo_ft_scaled_font_lock_face(sf); if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { From 10db8f0662c53954c66c6e3b5a8d57f6ff0ac2b6 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 1 Jun 2018 15:37:23 -0400 Subject: [PATCH 074/116] Bug 1392106 - Tweak the fuzzing conditions for clipping-6.html to work around win10-qr reftest failures. r=jmaher --- layout/reftests/border-radius/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/border-radius/reftest.list b/layout/reftests/border-radius/reftest.list index 7f37662adb5d..8434df78eeee 100644 --- a/layout/reftests/border-radius/reftest.list +++ b/layout/reftests/border-radius/reftest.list @@ -51,7 +51,7 @@ fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-5-image.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(skiaContent,1,77) == clipping-5-overflow-hidden.html clipping-5-ref.html fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) fuzzy-if(Android,5,21) fuzzy-if(skiaContent,1,97) == clipping-5-refi.html clipping-5-ref.html fuzzy-if(true,1,7) fuzzy-if(d2d,55,95) fuzzy-if(cocoaWidget,1,99) fuzzy-if(Android,99,115) fuzzy-if(skiaContent,1,77) == clipping-5-refc.html clipping-5-ref.html # bug 732535 -fuzzy-if(winWidget,105,335) fuzzy-if(Android,8,469) fuzzy-if(skiaContent,21,74) fuzzy-if(d3d11&&advancedLayers,120,319) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical, bug 1392106 +fuzzy-if(Android,8,469) fuzzy-if(skiaContent,21,74) fuzzy-if(winWidget,144,335) fuzzy-if(webrender&&cocoaWidget,98-98,279-279) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == clipping-6.html clipping-6-ref.html # PaintedLayer and MaskLayer with transforms that aren't identical, bug 1392106 fuzzy-if(true,2,29) fuzzy-if(d2d,46,71) fuzzy-if(Android,255,586) fuzzy-if(skiaContent,28,96) == clipping-7.html clipping-7-ref.html # ColorLayer and MaskLayer with transforms that aren't identical. Reference image rendered without using layers (which causes fuzzy failures). fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,5) == clipping-and-zindex-1.html clipping-and-zindex-1-ref.html fuzzy-if(cocoaWidget,1,4) fuzzy-if(d2d,59,342) fuzzy-if(d3d11&&advancedLayers&&!d2d,30,3) == intersecting-clipping-1-canvas.html intersecting-clipping-1-refc.html From 5cf423733305cd63e8b604e50dcb40f967dec71f Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 1 Jun 2018 15:39:50 -0400 Subject: [PATCH 075/116] Bug 1464094 - follow-up - check that dlsym succeeded in ApplyVariations. r=me MozReview-Commit-ID: 5lrrnFVKMS0 --- gfx/2d/ScaledFontFontconfig.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/2d/ScaledFontFontconfig.cpp b/gfx/2d/ScaledFontFontconfig.cpp index 04d4e16ea30d..27256d36f7ee 100644 --- a/gfx/2d/ScaledFontFontconfig.cpp +++ b/gfx/2d/ScaledFontFontconfig.cpp @@ -589,6 +589,10 @@ ScaledFontFontconfig::ApplyVariations(const FontVariation* aVariations, setCoords = (SetVarDesignCoordsFunc)dlsym(RTLD_DEFAULT, "FT_Set_Var_Design_Coordinates"); } + if (!setCoords) { + return; + } + cairo_scaled_font_t* sf = GetCairoScaledFont(); FT_Face face = cairo_ft_scaled_font_lock_face(sf); if (face && face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { From 121d7193a480be1f927c2cf6762a35aa6e48a04d Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 1 Jun 2018 15:52:26 -0400 Subject: [PATCH 076/116] Bug 1465686 - validate SkArenaAlloc sizes. r=rhunt MozReview-Commit-ID: Cc4cxKeF4xn --- gfx/skia/skia/src/core/SkArenaAlloc.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gfx/skia/skia/src/core/SkArenaAlloc.h b/gfx/skia/skia/src/core/SkArenaAlloc.h index c9e7274e63de..b93054cff017 100644 --- a/gfx/skia/skia/src/core/SkArenaAlloc.h +++ b/gfx/skia/skia/src/core/SkArenaAlloc.h @@ -112,9 +112,14 @@ public: return sk_sp(SkRef(this->make(std::forward(args)...))); } + uint32_t safeU32(size_t n) { + SkASSERT_RELEASE(SkTFitsIn(n)); + return uint32_t(n); + } + template T* makeArrayDefault(size_t count) { - uint32_t safeCount = SkTo(count); + uint32_t safeCount = safeU32(count); T* array = (T*)this->commonArrayAlloc(safeCount); // If T is primitive then no initialization takes place. @@ -126,7 +131,7 @@ public: template T* makeArray(size_t count) { - uint32_t safeCount = SkTo(count); + uint32_t safeCount = safeU32(count); T* array = (T*)this->commonArrayAlloc(safeCount); // If T is primitive then the memory is initialized. For example, an array of chars will @@ -139,7 +144,7 @@ public: // Only use makeBytesAlignedTo if none of the typed variants are impractical to use. void* makeBytesAlignedTo(size_t size, size_t align) { - auto objStart = this->allocObject(SkTo(size), SkTo(align)); + auto objStart = this->allocObject(safeU32(size), safeU32(align)); fCursor = objStart + size; return objStart; } From 6a3f757203a2561dbaf99c4864d1eee6819da173 Mon Sep 17 00:00:00 2001 From: Gabriel Luong Date: Fri, 1 Jun 2018 15:58:04 -0400 Subject: [PATCH 077/116] Bug 1465810 - Update Codemirror to 5.38.0. r=bgrins --- .../codemirror/addon/dialog/dialog.js | 4 + .../codemirror/addon/hint/show-hint.js | 2 +- .../codemirror/addon/runmode/runmode.js | 2 +- .../codemirror/codemirror.bundle.js | 22555 +--------------- .../sourceeditor/codemirror/lib/codemirror.js | 58 +- .../codemirror/mode/javascript/javascript.js | 90 +- .../test/codemirror/mode/javascript/test.js | 31 + .../sourceeditor/test/codemirror/test.js | 9 + 8 files changed, 143 insertions(+), 22608 deletions(-) diff --git a/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js b/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js index f10bb5bf190b..f61e447660a2 100644 --- a/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js +++ b/devtools/client/sourceeditor/codemirror/addon/dialog/dialog.js @@ -25,6 +25,7 @@ } else { // Assuming it's a detached DOM element. dialog.appendChild(template); } + CodeMirror.addClass(wrap, 'dialog-opened'); return dialog; } @@ -47,6 +48,7 @@ } else { if (closed) return; closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); dialog.parentNode.removeChild(dialog); me.focus(); @@ -102,6 +104,7 @@ function close() { if (closed) return; closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); dialog.parentNode.removeChild(dialog); me.focus(); } @@ -141,6 +144,7 @@ if (closed) return; closed = true; clearTimeout(doneTimer); + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); dialog.parentNode.removeChild(dialog); } diff --git a/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js b/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js index 81a63fc9921e..dae450db90f2 100644 --- a/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js +++ b/devtools/client/sourceeditor/codemirror/addon/hint/show-hint.js @@ -333,7 +333,7 @@ i = avoidWrap ? 0 : this.data.list.length - 1; if (this.selectedHint == i) return; var node = this.hints.childNodes[this.selectedHint]; - node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); node = this.hints.childNodes[this.selectedHint = i]; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; if (node.offsetTop < this.hints.scrollTop) diff --git a/devtools/client/sourceeditor/codemirror/addon/runmode/runmode.js b/devtools/client/sourceeditor/codemirror/addon/runmode/runmode.js index 5540a2531fc7..a51c6d0d5229 100644 --- a/devtools/client/sourceeditor/codemirror/addon/runmode/runmode.js +++ b/devtools/client/sourceeditor/codemirror/addon/runmode/runmode.js @@ -69,4 +69,4 @@ CodeMirror.runMode = function(string, modespec, callback, options) { } }; -}); \ No newline at end of file +}); diff --git a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js index f327afebda71..b3e5674b7377 100644 --- a/devtools/client/sourceeditor/codemirror/codemirror.bundle.js +++ b/devtools/client/sourceeditor/codemirror/codemirror.bundle.js @@ -1,22554 +1 @@ -var CodeMirror = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; - -/******/ // The require function -/******/ function __webpack_require__(moduleId) { - -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; - -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ exports: {}, -/******/ id: moduleId, -/******/ loaded: false -/******/ }; - -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -/******/ // Flag the module as loaded -/******/ module.loaded = true; - -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } - - -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; - -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; - -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; - -/******/ // Load entry module and return exports -/******/ return __webpack_require__(0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - - __webpack_require__(1); - __webpack_require__(3); - __webpack_require__(4); - __webpack_require__(5); - __webpack_require__(6); - __webpack_require__(7); - __webpack_require__(8); - __webpack_require__(9); - __webpack_require__(10); - __webpack_require__(11); - __webpack_require__(12); - __webpack_require__(13); - __webpack_require__(14); - __webpack_require__(15); - __webpack_require__(16); - __webpack_require__(17); - __webpack_require__(18); - __webpack_require__(19); - __webpack_require__(20); - __webpack_require__(21); - __webpack_require__(22); - __webpack_require__(23); - __webpack_require__(24); - __webpack_require__(25); - __webpack_require__(26); - __webpack_require__(27); - module.exports = __webpack_require__(2); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - // Open simple dialogs on top of an editor. Relies on dialog.css. - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - function dialogDiv(cm, template, bottom) { - var wrap = cm.getWrapperElement(); - var dialog; - dialog = wrap.appendChild(document.createElement("div")); - if (bottom) - dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; - else - dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; - - if (typeof template == "string") { - dialog.innerHTML = template; - } else { // Assuming it's a detached DOM element. - dialog.appendChild(template); - } - return dialog; - } - - function closeNotification(cm, newVal) { - if (cm.state.currentNotificationClose) - cm.state.currentNotificationClose(); - cm.state.currentNotificationClose = newVal; - } - - CodeMirror.defineExtension("openDialog", function(template, callback, options) { - if (!options) options = {}; - - closeNotification(this, null); - - var dialog = dialogDiv(this, template, options.bottom); - var closed = false, me = this; - function close(newVal) { - if (typeof newVal == 'string') { - inp.value = newVal; - } else { - if (closed) return; - closed = true; - dialog.parentNode.removeChild(dialog); - me.focus(); - - if (options.onClose) options.onClose(dialog); - } - } - - var inp = dialog.getElementsByTagName("input")[0], button; - if (inp) { - inp.focus(); - - if (options.value) { - inp.value = options.value; - if (options.selectValueOnOpen !== false) { - inp.select(); - } - } - - if (options.onInput) - CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); - if (options.onKeyUp) - CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); - - CodeMirror.on(inp, "keydown", function(e) { - if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } - if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { - inp.blur(); - CodeMirror.e_stop(e); - close(); - } - if (e.keyCode == 13) callback(inp.value, e); - }); - - if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); - } else if (button = dialog.getElementsByTagName("button")[0]) { - CodeMirror.on(button, "click", function() { - close(); - me.focus(); - }); - - if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); - - button.focus(); - } - return close; - }); - - CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { - closeNotification(this, null); - var dialog = dialogDiv(this, template, options && options.bottom); - var buttons = dialog.getElementsByTagName("button"); - var closed = false, me = this, blurring = 1; - function close() { - if (closed) return; - closed = true; - dialog.parentNode.removeChild(dialog); - me.focus(); - } - buttons[0].focus(); - for (var i = 0; i < buttons.length; ++i) { - var b = buttons[i]; - (function(callback) { - CodeMirror.on(b, "click", function(e) { - CodeMirror.e_preventDefault(e); - close(); - if (callback) callback(me); - }); - })(callbacks[i]); - CodeMirror.on(b, "blur", function() { - --blurring; - setTimeout(function() { if (blurring <= 0) close(); }, 200); - }); - CodeMirror.on(b, "focus", function() { ++blurring; }); - } - }); - - /* - * openNotification - * Opens a notification, that can be closed with an optional timer - * (default 5000ms timer) and always closes on click. - * - * If a notification is opened while another is opened, it will close the - * currently opened one and open the new one immediately. - */ - CodeMirror.defineExtension("openNotification", function(template, options) { - closeNotification(this, close); - var dialog = dialogDiv(this, template, options && options.bottom); - var closed = false, doneTimer; - var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; - - function close() { - if (closed) return; - closed = true; - clearTimeout(doneTimer); - dialog.parentNode.removeChild(dialog); - } - - CodeMirror.on(dialog, 'click', function(e) { - CodeMirror.e_preventDefault(e); - close(); - }); - - if (duration) - doneTimer = setTimeout(close, duration); - - return close; - }); - }); - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - // This is CodeMirror (http://codemirror.net), a code editor - // implemented in JavaScript on top of the browser's DOM. - // - // You can find some technical background for some of the code below - // at http://marijnhaverbeke.nl/blog/#cm-internals . - - (function (global, factory) { - true ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global.CodeMirror = factory()); - }(this, (function () { 'use strict'; - - // Kludges for bugs and behavior differences that can't be feature - // detected are enabled based on userAgent etc sniffing. - var userAgent = navigator.userAgent - var platform = navigator.platform - - var gecko = /gecko\/\d/i.test(userAgent) - var ie_upto10 = /MSIE \d/.test(userAgent) - var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) - var edge = /Edge\/(\d+)/.exec(userAgent) - var ie = ie_upto10 || ie_11up || edge - var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]) - var webkit = !edge && /WebKit\//.test(userAgent) - var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) - var chrome = !edge && /Chrome\//.test(userAgent) - var presto = /Opera\//.test(userAgent) - var safari = /Apple Computer/.test(navigator.vendor) - var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) - var phantom = /PhantomJS/.test(userAgent) - - var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) - var android = /Android/.test(userAgent) - // This is woefully incomplete. Suggestions for alternative methods welcome. - var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) - var mac = ios || /Mac/.test(platform) - var chromeOS = /\bCrOS\b/.test(userAgent) - var windows = /win/i.test(platform) - - var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) - if (presto_version) { presto_version = Number(presto_version[1]) } - if (presto_version && presto_version >= 15) { presto = false; webkit = true } - // Some browsers use the wrong event properties to signal cmd/ctrl on OS X - var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) - var captureRightClick = gecko || (ie && ie_version >= 9) - - function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } - - var rmClass = function(node, cls) { - var current = node.className - var match = classTest(cls).exec(current) - if (match) { - var after = current.slice(match.index + match[0].length) - node.className = current.slice(0, match.index) + (after ? match[1] + after : "") - } - } - - function removeChildren(e) { - for (var count = e.childNodes.length; count > 0; --count) - { e.removeChild(e.firstChild) } - return e - } - - function removeChildrenAndAdd(parent, e) { - return removeChildren(parent).appendChild(e) - } - - function elt(tag, content, className, style) { - var e = document.createElement(tag) - if (className) { e.className = className } - if (style) { e.style.cssText = style } - if (typeof content == "string") { e.appendChild(document.createTextNode(content)) } - else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } } - return e - } - // wrapper for elt, which removes the elt from the accessibility tree - function eltP(tag, content, className, style) { - var e = elt(tag, content, className, style) - e.setAttribute("role", "presentation") - return e - } - - var range - if (document.createRange) { range = function(node, start, end, endNode) { - var r = document.createRange() - r.setEnd(endNode || node, end) - r.setStart(node, start) - return r - } } - else { range = function(node, start, end) { - var r = document.body.createTextRange() - try { r.moveToElementText(node.parentNode) } - catch(e) { return r } - r.collapse(true) - r.moveEnd("character", end) - r.moveStart("character", start) - return r - } } - - function contains(parent, child) { - if (child.nodeType == 3) // Android browser always returns false when child is a textnode - { child = child.parentNode } - if (parent.contains) - { return parent.contains(child) } - do { - if (child.nodeType == 11) { child = child.host } - if (child == parent) { return true } - } while (child = child.parentNode) - } - - function activeElt() { - // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. - // IE < 10 will throw when accessed while the page is loading or in an iframe. - // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. - var activeElement - try { - activeElement = document.activeElement - } catch(e) { - activeElement = document.body || null - } - while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) - { activeElement = activeElement.shadowRoot.activeElement } - return activeElement - } - - function addClass(node, cls) { - var current = node.className - if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls } - } - function joinClasses(a, b) { - var as = a.split(" ") - for (var i = 0; i < as.length; i++) - { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } } - return b - } - - var selectInput = function(node) { node.select() } - if (ios) // Mobile Safari apparently has a bug where select() is broken. - { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } } - else if (ie) // Suppress mysterious IE10 errors - { selectInput = function(node) { try { node.select() } catch(_e) {} } } - - function bind(f) { - var args = Array.prototype.slice.call(arguments, 1) - return function(){return f.apply(null, args)} - } - - function copyObj(obj, target, overwrite) { - if (!target) { target = {} } - for (var prop in obj) - { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) - { target[prop] = obj[prop] } } - return target - } - - // Counts the column offset in a string, taking tabs into account. - // Used mostly to find indentation. - function countColumn(string, end, tabSize, startIndex, startValue) { - if (end == null) { - end = string.search(/[^\s\u00a0]/) - if (end == -1) { end = string.length } - } - for (var i = startIndex || 0, n = startValue || 0;;) { - var nextTab = string.indexOf("\t", i) - if (nextTab < 0 || nextTab >= end) - { return n + (end - i) } - n += nextTab - i - n += tabSize - (n % tabSize) - i = nextTab + 1 - } - } - - var Delayed = function() {this.id = null}; - Delayed.prototype.set = function (ms, f) { - clearTimeout(this.id) - this.id = setTimeout(f, ms) - }; - - function indexOf(array, elt) { - for (var i = 0; i < array.length; ++i) - { if (array[i] == elt) { return i } } - return -1 - } - - // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30 - - // Returned or thrown by various protocols to signal 'I'm not - // handling this'. - var Pass = {toString: function(){return "CodeMirror.Pass"}} - - // Reused option objects for setSelection & friends - var sel_dontScroll = {scroll: false}; - var sel_mouse = {origin: "*mouse"}; - var sel_move = {origin: "+move"}; - // The inverse of countColumn -- find the offset that corresponds to - // a particular column. - function findColumn(string, goal, tabSize) { - for (var pos = 0, col = 0;;) { - var nextTab = string.indexOf("\t", pos) - if (nextTab == -1) { nextTab = string.length } - var skipped = nextTab - pos - if (nextTab == string.length || col + skipped >= goal) - { return pos + Math.min(skipped, goal - col) } - col += nextTab - pos - col += tabSize - (col % tabSize) - pos = nextTab + 1 - if (col >= goal) { return pos } - } - } - - var spaceStrs = [""] - function spaceStr(n) { - while (spaceStrs.length <= n) - { spaceStrs.push(lst(spaceStrs) + " ") } - return spaceStrs[n] - } - - function lst(arr) { return arr[arr.length-1] } - - function map(array, f) { - var out = [] - for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) } - return out - } - - function insertSorted(array, value, score) { - var pos = 0, priority = score(value) - while (pos < array.length && score(array[pos]) <= priority) { pos++ } - array.splice(pos, 0, value) - } - - function nothing() {} - - function createObj(base, props) { - var inst - if (Object.create) { - inst = Object.create(base) - } else { - nothing.prototype = base - inst = new nothing() - } - if (props) { copyObj(props, inst) } - return inst - } - - var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ - function isWordCharBasic(ch) { - return /\w/.test(ch) || ch > "\x80" && - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) - } - function isWordChar(ch, helper) { - if (!helper) { return isWordCharBasic(ch) } - if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true } - return helper.test(ch) - } - - function isEmpty(obj) { - for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } } - return true - } - - // Extending unicode characters. A series of a non-extending char + - // any number of extending chars is treated as a single unit as far - // as editing and measuring is concerned. This is not fully correct, - // since some scripts/fonts/browsers also treat other configurations - // of code points as a group. - var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ - function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } - - // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range. - function skipExtendingChars(str, pos, dir) { - while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir } - return pos - } - - // Returns the value from the range [`from`; `to`] that satisfies - // `pred` and is closest to `from`. Assumes that at least `to` - // satisfies `pred`. Supports `from` being greater than `to`. - function findFirst(pred, from, to) { - // At any point we are certain `to` satisfies `pred`, don't know - // whether `from` does. - var dir = from > to ? -1 : 1 - for (;;) { - if (from == to) { return from } - var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF) - if (mid == from) { return pred(mid) ? from : to } - if (pred(mid)) { to = mid } - else { from = mid + dir } - } - } - - // The display handles the DOM integration, both for input reading - // and content drawing. It holds references to DOM nodes and - // display-related state. - - function Display(place, doc, input) { - var d = this - this.input = input - - // Covers bottom-right square when both scrollbars are present. - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler") - d.scrollbarFiller.setAttribute("cm-not-content", "true") - // Covers bottom of gutter when coverGutterNextToScrollbar is on - // and h scrollbar is present. - d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler") - d.gutterFiller.setAttribute("cm-not-content", "true") - // Will contain the actual code, positioned to cover the viewport. - d.lineDiv = eltP("div", null, "CodeMirror-code") - // Elements are added to these to represent selection and cursors. - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1") - d.cursorDiv = elt("div", null, "CodeMirror-cursors") - // A visibility: hidden element used to find the size of things. - d.measure = elt("div", null, "CodeMirror-measure") - // When lines outside of the viewport are measured, they are drawn in this. - d.lineMeasure = elt("div", null, "CodeMirror-measure") - // Wraps everything that needs to exist inside the vertically-padded coordinate system - d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], - null, "position: relative; outline: none") - var lines = eltP("div", [d.lineSpace], "CodeMirror-lines") - // Moved around its parent to cover visible view. - d.mover = elt("div", [lines], null, "position: relative") - // Set to the height of the document, allowing scrolling. - d.sizer = elt("div", [d.mover], "CodeMirror-sizer") - d.sizerWidth = null - // Behavior of elts with overflow: auto and padding is - // inconsistent across browsers. This is used to ensure the - // scrollable area is big enough. - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;") - // Will contain the gutters, if any. - d.gutters = elt("div", null, "CodeMirror-gutters") - d.lineGutter = null - // Actual scrollable element. - d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll") - d.scroller.setAttribute("tabIndex", "-1") - // The element in which the editor lives. - d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror") - - // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) - if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 } - if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true } - - if (place) { - if (place.appendChild) { place.appendChild(d.wrapper) } - else { place(d.wrapper) } - } - - // Current rendered range (may be bigger than the view window). - d.viewFrom = d.viewTo = doc.first - d.reportedViewFrom = d.reportedViewTo = doc.first - // Information about the rendered lines. - d.view = [] - d.renderedView = null - // Holds info about a single rendered line when it was rendered - // for measurement, while not in view. - d.externalMeasured = null - // Empty space (in pixels) above the view - d.viewOffset = 0 - d.lastWrapHeight = d.lastWrapWidth = 0 - d.updateLineNumbers = null - - d.nativeBarWidth = d.barHeight = d.barWidth = 0 - d.scrollbarsClipped = false - - // Used to only resize the line number gutter when necessary (when - // the amount of lines crosses a boundary that makes its width change) - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null - // Set to true when a non-horizontal-scrolling line widget is - // added. As an optimization, line widget aligning is skipped when - // this is false. - d.alignWidgets = false - - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null - - // Tracks the maximum line length so that the horizontal scrollbar - // can be kept static when scrolling. - d.maxLine = null - d.maxLineLength = 0 - d.maxLineChanged = false - - // Used for measuring wheel scrolling granularity - d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null - - // True when shift is held down. - d.shift = false - - // Used to track whether anything happened since the context menu - // was opened. - d.selForContextMenu = null - - d.activeTouch = null - - input.init(d) - } - - // Find the line object corresponding to the given line number. - function getLine(doc, n) { - n -= doc.first - if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") } - var chunk = doc - while (!chunk.lines) { - for (var i = 0;; ++i) { - var child = chunk.children[i], sz = child.chunkSize() - if (n < sz) { chunk = child; break } - n -= sz - } - } - return chunk.lines[n] - } - - // Get the part of a document between two positions, as an array of - // strings. - function getBetween(doc, start, end) { - var out = [], n = start.line - doc.iter(start.line, end.line + 1, function (line) { - var text = line.text - if (n == end.line) { text = text.slice(0, end.ch) } - if (n == start.line) { text = text.slice(start.ch) } - out.push(text) - ++n - }) - return out - } - // Get the lines between from and to, as array of strings. - function getLines(doc, from, to) { - var out = [] - doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value - return out - } - - // Update the height of a line, propagating the height change - // upwards to parent nodes. - function updateLineHeight(line, height) { - var diff = height - line.height - if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } } - } - - // Given a line object, find its line number by walking up through - // its parent links. - function lineNo(line) { - if (line.parent == null) { return null } - var cur = line.parent, no = indexOf(cur.lines, line) - for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { - for (var i = 0;; ++i) { - if (chunk.children[i] == cur) { break } - no += chunk.children[i].chunkSize() - } - } - return no + cur.first - } - - // Find the line at the given vertical position, using the height - // information in the document tree. - function lineAtHeight(chunk, h) { - var n = chunk.first - outer: do { - for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) { - var child = chunk.children[i$1], ch = child.height - if (h < ch) { chunk = child; continue outer } - h -= ch - n += child.chunkSize() - } - return n - } while (!chunk.lines) - var i = 0 - for (; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height - if (h < lh) { break } - h -= lh - } - return n + i - } - - function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} - - function lineNumberFor(options, i) { - return String(options.lineNumberFormatter(i + options.firstLineNumber)) - } - - // A Pos instance represents a position within the text. - function Pos(line, ch, sticky) { - if ( sticky === void 0 ) sticky = null; - - if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) } - this.line = line - this.ch = ch - this.sticky = sticky - } - - // Compare two positions, return 0 if they are the same, a negative - // number when a is less, and a positive number otherwise. - function cmp(a, b) { return a.line - b.line || a.ch - b.ch } - - function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 } - - function copyPos(x) {return Pos(x.line, x.ch)} - function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } - function minPos(a, b) { return cmp(a, b) < 0 ? a : b } - - // Most of the external API clips given positions to make sure they - // actually exist within the document. - function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} - function clipPos(doc, pos) { - if (pos.line < doc.first) { return Pos(doc.first, 0) } - var last = doc.first + doc.size - 1 - if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) } - return clipToLen(pos, getLine(doc, pos.line).text.length) - } - function clipToLen(pos, linelen) { - var ch = pos.ch - if (ch == null || ch > linelen) { return Pos(pos.line, linelen) } - else if (ch < 0) { return Pos(pos.line, 0) } - else { return pos } - } - function clipPosArray(doc, array) { - var out = [] - for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) } - return out - } - - // Optimize some code when these features are not used. - var sawReadOnlySpans = false; - var sawCollapsedSpans = false; - function seeReadOnlySpans() { - sawReadOnlySpans = true - } - - function seeCollapsedSpans() { - sawCollapsedSpans = true - } - - // TEXTMARKER SPANS - - function MarkedSpan(marker, from, to) { - this.marker = marker - this.from = from; this.to = to - } - - // Search an array of spans for a span matching the given marker. - function getMarkedSpanFor(spans, marker) { - if (spans) { for (var i = 0; i < spans.length; ++i) { - var span = spans[i] - if (span.marker == marker) { return span } - } } - } - // Remove a span from an array, returning undefined if no spans are - // left (we don't store arrays for lines without spans). - function removeMarkedSpan(spans, span) { - var r - for (var i = 0; i < spans.length; ++i) - { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } } - return r - } - // Add a span to a line. - function addMarkedSpan(line, span) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span] - span.marker.attachLine(line) - } - - // Used for the algorithm that adjusts markers for a change in the - // document. These functions cut an array of spans at a given - // character position, returning an array of remaining chunks (or - // undefined if nothing remains). - function markedSpansBefore(old, startCh, isInsert) { - var nw - if (old) { for (var i = 0; i < old.length; ++i) { - var span = old[i], marker = span.marker - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh) - if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) - ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)) - } - } } - return nw - } - function markedSpansAfter(old, endCh, isInsert) { - var nw - if (old) { for (var i = 0; i < old.length; ++i) { - var span = old[i], marker = span.marker - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) - if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) - ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, - span.to == null ? null : span.to - endCh)) - } - } } - return nw - } - - // Given a change object, compute the new set of marker spans that - // cover the line in which the change took place. Removes spans - // entirely within the change, reconnects spans belonging to the - // same marker that appear on both sides of the change, and cuts off - // spans partially within the change. Returns an array of span - // arrays with one element for each line in (after) the change. - function stretchSpansOverChange(doc, change) { - if (change.full) { return null } - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans - if (!oldFirst && !oldLast) { return null } - - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 - // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert) - var last = markedSpansAfter(oldLast, endCh, isInsert) - - // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) - if (first) { - // Fix up .to properties of first - for (var i = 0; i < first.length; ++i) { - var span = first[i] - if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker) - if (!found) { span.to = startCh } - else if (sameLine) { span.to = found.to == null ? null : found.to + offset } - } - } - } - if (last) { - // Fix up .from in last (or move them into first in case of sameLine) - for (var i$1 = 0; i$1 < last.length; ++i$1) { - var span$1 = last[i$1] - if (span$1.to != null) { span$1.to += offset } - if (span$1.from == null) { - var found$1 = getMarkedSpanFor(first, span$1.marker) - if (!found$1) { - span$1.from = offset - if (sameLine) { (first || (first = [])).push(span$1) } - } - } else { - span$1.from += offset - if (sameLine) { (first || (first = [])).push(span$1) } - } - } - } - // Make sure we didn't create any zero-length spans - if (first) { first = clearEmptySpans(first) } - if (last && last != first) { last = clearEmptySpans(last) } - - var newMarkers = [first] - if (!sameLine) { - // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers - if (gap > 0 && first) - { for (var i$2 = 0; i$2 < first.length; ++i$2) - { if (first[i$2].to == null) - { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } } - for (var i$3 = 0; i$3 < gap; ++i$3) - { newMarkers.push(gapMarkers) } - newMarkers.push(last) - } - return newMarkers - } - - // Remove spans that are empty and don't have a clearWhenEmpty - // option of false. - function clearEmptySpans(spans) { - for (var i = 0; i < spans.length; ++i) { - var span = spans[i] - if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) - { spans.splice(i--, 1) } - } - if (!spans.length) { return null } - return spans - } - - // Used to 'clip' out readOnly ranges when making a change. - function removeReadOnlyRanges(doc, from, to) { - var markers = null - doc.iter(from.line, to.line + 1, function (line) { - if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker - if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) - { (markers || (markers = [])).push(mark) } - } } - }) - if (!markers) { return null } - var parts = [{from: from, to: to}] - for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0) - for (var j = 0; j < parts.length; ++j) { - var p = parts[j] - if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue } - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) - if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) - { newParts.push({from: p.from, to: m.from}) } - if (dto > 0 || !mk.inclusiveRight && !dto) - { newParts.push({from: m.to, to: p.to}) } - parts.splice.apply(parts, newParts) - j += newParts.length - 3 - } - } - return parts - } - - // Connect or disconnect spans from a line. - function detachMarkedSpans(line) { - var spans = line.markedSpans - if (!spans) { return } - for (var i = 0; i < spans.length; ++i) - { spans[i].marker.detachLine(line) } - line.markedSpans = null - } - function attachMarkedSpans(line, spans) { - if (!spans) { return } - for (var i = 0; i < spans.length; ++i) - { spans[i].marker.attachLine(line) } - line.markedSpans = spans - } - - // Helpers used when computing which overlapping collapsed span - // counts as the larger one. - function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } - function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } - - // Returns a number indicating which of two overlapping collapsed - // spans is larger (and thus includes the other). Falls back to - // comparing ids when the spans cover exactly the same range. - function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length - if (lenDiff != 0) { return lenDiff } - var aPos = a.find(), bPos = b.find() - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) - if (fromCmp) { return -fromCmp } - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) - if (toCmp) { return toCmp } - return b.id - a.id - } - - // Find out whether a line ends or starts in a collapsed span. If - // so, return the marker for that span. - function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found - if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { - sp = sps[i] - if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && - (!found || compareCollapsedMarkers(found, sp.marker) < 0)) - { found = sp.marker } - } } - return found - } - function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } - function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } - - // Test whether there exists a collapsed span that partially - // overlaps (covers the start or end, but not both) of a new span. - // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo) - var sps = sawCollapsedSpans && line.markedSpans - if (sps) { for (var i = 0; i < sps.length; ++i) { - var sp = sps[i] - if (!sp.marker.collapsed) { continue } - var found = sp.marker.find(0) - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) - if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue } - if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || - fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) - { return true } - } } - } - - // A visual line is a line as drawn on the screen. Folding, for - // example, can cause multiple logical lines to appear on the same - // visual line. This finds the start of the visual line that the - // given line is part of (usually that is the line itself). - function visualLine(line) { - var merged - while (merged = collapsedSpanAtStart(line)) - { line = merged.find(-1, true).line } - return line - } - - function visualLineEnd(line) { - var merged - while (merged = collapsedSpanAtEnd(line)) - { line = merged.find(1, true).line } - return line - } - - // Returns an array of logical lines that continue the visual line - // started by the argument, or undefined if there are no such lines. - function visualLineContinued(line) { - var merged, lines - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line - ;(lines || (lines = [])).push(line) - } - return lines - } - - // Get the line number of the start of the visual line that the - // given line number is part of. - function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line) - if (line == vis) { return lineN } - return lineNo(vis) - } - - // Get the line number of the start of the next visual line after - // the given line. - function visualLineEndNo(doc, lineN) { - if (lineN > doc.lastLine()) { return lineN } - var line = getLine(doc, lineN), merged - if (!lineIsHidden(doc, line)) { return lineN } - while (merged = collapsedSpanAtEnd(line)) - { line = merged.find(1, true).line } - return lineNo(line) + 1 - } - - // Compute whether a line is hidden. Lines count as hidden when they - // are part of a visual line that starts with another line, or when - // they are entirely covered by collapsed, non-widget span. - function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans - if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { - sp = sps[i] - if (!sp.marker.collapsed) { continue } - if (sp.from == null) { return true } - if (sp.marker.widgetNode) { continue } - if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) - { return true } - } } - } - function lineIsHiddenInner(doc, line, span) { - if (span.to == null) { - var end = span.marker.find(1, true) - return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) - } - if (span.marker.inclusiveRight && span.to == line.text.length) - { return true } - for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) { - sp = line.markedSpans[i] - if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && - (sp.to == null || sp.to != span.from) && - (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && - lineIsHiddenInner(doc, line, sp)) { return true } - } - } - - // Find the height above the given line. - function heightAtLine(lineObj) { - lineObj = visualLine(lineObj) - - var h = 0, chunk = lineObj.parent - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i] - if (line == lineObj) { break } - else { h += line.height } - } - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { - for (var i$1 = 0; i$1 < p.children.length; ++i$1) { - var cur = p.children[i$1] - if (cur == chunk) { break } - else { h += cur.height } - } - } - return h - } - - // Compute the character length of a line, taking into account - // collapsed ranges (see markText) that might hide parts, and join - // other lines onto it. - function lineLength(line) { - if (line.height == 0) { return 0 } - var len = line.text.length, merged, cur = line - while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true) - cur = found.from.line - len += found.from.ch - found.to.ch - } - cur = line - while (merged = collapsedSpanAtEnd(cur)) { - var found$1 = merged.find(0, true) - len -= cur.text.length - found$1.from.ch - cur = found$1.to.line - len += cur.text.length - found$1.to.ch - } - return len - } - - // Find the longest line in the document. - function findMaxLine(cm) { - var d = cm.display, doc = cm.doc - d.maxLine = getLine(doc, doc.first) - d.maxLineLength = lineLength(d.maxLine) - d.maxLineChanged = true - doc.iter(function (line) { - var len = lineLength(line) - if (len > d.maxLineLength) { - d.maxLineLength = len - d.maxLine = line - } - }) - } - - // BIDI HELPERS - - function iterateBidiSections(order, from, to, f) { - if (!order) { return f(from, to, "ltr", 0) } - var found = false - for (var i = 0; i < order.length; ++i) { - var part = order[i] - if (part.from < to && part.to > from || from == to && part.to == from) { - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i) - found = true - } - } - if (!found) { f(from, to, "ltr") } - } - - var bidiOther = null - function getBidiPartAt(order, ch, sticky) { - var found - bidiOther = null - for (var i = 0; i < order.length; ++i) { - var cur = order[i] - if (cur.from < ch && cur.to > ch) { return i } - if (cur.to == ch) { - if (cur.from != cur.to && sticky == "before") { found = i } - else { bidiOther = i } - } - if (cur.from == ch) { - if (cur.from != cur.to && sticky != "before") { found = i } - else { bidiOther = i } - } - } - return found != null ? found : bidiOther - } - - // Bidirectional ordering algorithm - // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm - // that this (partially) implements. - - // One-char codes used for character types: - // L (L): Left-to-Right - // R (R): Right-to-Left - // r (AL): Right-to-Left Arabic - // 1 (EN): European Number - // + (ES): European Number Separator - // % (ET): European Number Terminator - // n (AN): Arabic Number - // , (CS): Common Number Separator - // m (NSM): Non-Spacing Mark - // b (BN): Boundary Neutral - // s (B): Paragraph Separator - // t (S): Segment Separator - // w (WS): Whitespace - // N (ON): Other Neutrals - - // Returns null if characters are ordered as they appear - // (left-to-right), or an array of sections ({from, to, level} - // objects) in the order in which they occur visually. - var bidiOrdering = (function() { - // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" - // Character types for codepoints 0x600 to 0x6f9 - var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111" - function charType(code) { - if (code <= 0xf7) { return lowTypes.charAt(code) } - else if (0x590 <= code && code <= 0x5f4) { return "R" } - else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) } - else if (0x6ee <= code && code <= 0x8ac) { return "r" } - else if (0x2000 <= code && code <= 0x200b) { return "w" } - else if (code == 0x200c) { return "b" } - else { return "L" } - } - - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ - - function BidiSpan(level, from, to) { - this.level = level - this.from = from; this.to = to - } - - return function(str, direction) { - var outerType = direction == "ltr" ? "L" : "R" - - if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false } - var len = str.length, types = [] - for (var i = 0; i < len; ++i) - { types.push(charType(str.charCodeAt(i))) } - - // W1. Examine each non-spacing mark (NSM) in the level run, and - // change the type of the NSM to the type of the previous - // character. If the NSM is at the start of the level run, it will - // get the type of sor. - for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) { - var type = types[i$1] - if (type == "m") { types[i$1] = prev } - else { prev = type } - } - - // W2. Search backwards from each instance of a European number - // until the first strong type (R, L, AL, or sor) is found. If an - // AL is found, change the type of the European number to Arabic - // number. - // W3. Change all ALs to R. - for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) { - var type$1 = types[i$2] - if (type$1 == "1" && cur == "r") { types[i$2] = "n" } - else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } } - } - - // W4. A single European separator between two European numbers - // changes to a European number. A single common separator between - // two numbers of the same type changes to that type. - for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) { - var type$2 = types[i$3] - if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" } - else if (type$2 == "," && prev$1 == types[i$3+1] && - (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 } - prev$1 = type$2 - } - - // W5. A sequence of European terminators adjacent to European - // numbers changes to all European numbers. - // W6. Otherwise, separators and terminators change to Other - // Neutral. - for (var i$4 = 0; i$4 < len; ++i$4) { - var type$3 = types[i$4] - if (type$3 == ",") { types[i$4] = "N" } - else if (type$3 == "%") { - var end = (void 0) - for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {} - var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" - for (var j = i$4; j < end; ++j) { types[j] = replace } - i$4 = end - 1 - } - } - - // W7. Search backwards from each instance of a European number - // until the first strong type (R, L, or sor) is found. If an L is - // found, then change the type of the European number to L. - for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) { - var type$4 = types[i$5] - if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" } - else if (isStrong.test(type$4)) { cur$1 = type$4 } - } - - // N1. A sequence of neutrals takes the direction of the - // surrounding strong text if the text on both sides has the same - // direction. European and Arabic numbers act as if they were R in - // terms of their influence on neutrals. Start-of-level-run (sor) - // and end-of-level-run (eor) are used at level run boundaries. - // N2. Any remaining neutrals take the embedding direction. - for (var i$6 = 0; i$6 < len; ++i$6) { - if (isNeutral.test(types[i$6])) { - var end$1 = (void 0) - for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {} - var before = (i$6 ? types[i$6-1] : outerType) == "L" - var after = (end$1 < len ? types[end$1] : outerType) == "L" - var replace$1 = before == after ? (before ? "L" : "R") : outerType - for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 } - i$6 = end$1 - 1 - } - } - - // Here we depart from the documented algorithm, in order to avoid - // building up an actual levels array. Since there are only three - // levels (0, 1, 2) in an implementation that doesn't take - // explicit embedding into account, we can build up the order on - // the fly, without following the level-based algorithm. - var order = [], m - for (var i$7 = 0; i$7 < len;) { - if (countsAsLeft.test(types[i$7])) { - var start = i$7 - for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} - order.push(new BidiSpan(0, start, i$7)) - } else { - var pos = i$7, at = order.length - for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} - for (var j$2 = pos; j$2 < i$7;) { - if (countsAsNum.test(types[j$2])) { - if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) } - var nstart = j$2 - for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} - order.splice(at, 0, new BidiSpan(2, nstart, j$2)) - pos = j$2 - } else { ++j$2 } - } - if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) } - } - } - if (direction == "ltr") { - if (order[0].level == 1 && (m = str.match(/^\s+/))) { - order[0].from = m[0].length - order.unshift(new BidiSpan(0, 0, m[0].length)) - } - if (lst(order).level == 1 && (m = str.match(/\s+$/))) { - lst(order).to -= m[0].length - order.push(new BidiSpan(0, len - m[0].length, len)) - } - } - - return direction == "rtl" ? order.reverse() : order - } - })() - - // Get the bidi ordering for the given line (and cache it). Returns - // false for lines that are fully left-to-right, and an array of - // BidiSpan objects otherwise. - function getOrder(line, direction) { - var order = line.order - if (order == null) { order = line.order = bidiOrdering(line.text, direction) } - return order - } - - // EVENT HANDLING - - // Lightweight event framework. on/off also work on DOM nodes, - // registering native DOM handlers. - - var noHandlers = [] - - var on = function(emitter, type, f) { - if (emitter.addEventListener) { - emitter.addEventListener(type, f, false) - } else if (emitter.attachEvent) { - emitter.attachEvent("on" + type, f) - } else { - var map = emitter._handlers || (emitter._handlers = {}) - map[type] = (map[type] || noHandlers).concat(f) - } - } - - function getHandlers(emitter, type) { - return emitter._handlers && emitter._handlers[type] || noHandlers - } - - function off(emitter, type, f) { - if (emitter.removeEventListener) { - emitter.removeEventListener(type, f, false) - } else if (emitter.detachEvent) { - emitter.detachEvent("on" + type, f) - } else { - var map = emitter._handlers, arr = map && map[type] - if (arr) { - var index = indexOf(arr, f) - if (index > -1) - { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) } - } - } - } - - function signal(emitter, type /*, values...*/) { - var handlers = getHandlers(emitter, type) - if (!handlers.length) { return } - var args = Array.prototype.slice.call(arguments, 2) - for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) } - } - - // The DOM events that CodeMirror handles can be overridden by - // registering a (non-DOM) handler on the editor for the event name, - // and preventDefault-ing the event in that handler. - function signalDOMEvent(cm, e, override) { - if (typeof e == "string") - { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} } - signal(cm, override || e.type, cm, e) - return e_defaultPrevented(e) || e.codemirrorIgnore - } - - function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity - if (!arr) { return } - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) - for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1) - { set.push(arr[i]) } } - } - - function hasHandler(emitter, type) { - return getHandlers(emitter, type).length > 0 - } - - // Add on and off methods to a constructor's prototype, to make - // registering events on such objects more convenient. - function eventMixin(ctor) { - ctor.prototype.on = function(type, f) {on(this, type, f)} - ctor.prototype.off = function(type, f) {off(this, type, f)} - } - - // Due to the fact that we still support jurassic IE versions, some - // compatibility wrappers are needed. - - function e_preventDefault(e) { - if (e.preventDefault) { e.preventDefault() } - else { e.returnValue = false } - } - function e_stopPropagation(e) { - if (e.stopPropagation) { e.stopPropagation() } - else { e.cancelBubble = true } - } - function e_defaultPrevented(e) { - return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false - } - function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)} - - function e_target(e) {return e.target || e.srcElement} - function e_button(e) { - var b = e.which - if (b == null) { - if (e.button & 1) { b = 1 } - else if (e.button & 2) { b = 3 } - else if (e.button & 4) { b = 2 } - } - if (mac && e.ctrlKey && b == 1) { b = 3 } - return b - } - - // Detect drag-and-drop - var dragAndDrop = function() { - // There is *some* kind of drag-and-drop support in IE6-8, but I - // couldn't get it to work yet. - if (ie && ie_version < 9) { return false } - var div = elt('div') - return "draggable" in div || "dragDrop" in div - }() - - var zwspSupported - function zeroWidthElement(measure) { - if (zwspSupported == null) { - var test = elt("span", "\u200b") - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])) - if (measure.firstChild.offsetHeight != 0) - { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) } - } - var node = zwspSupported ? elt("span", "\u200b") : - elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px") - node.setAttribute("cm-text", "") - return node - } - - // Feature-detect IE's crummy client rect reporting for bidi text - var badBidiRects - function hasBadBidiRects(measure) { - if (badBidiRects != null) { return badBidiRects } - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) - var r0 = range(txt, 0, 1).getBoundingClientRect() - var r1 = range(txt, 1, 2).getBoundingClientRect() - removeChildren(measure) - if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780) - return badBidiRects = (r1.right - r0.right < 3) - } - - // See if "".split is the broken IE version, if so, provide an - // alternative way to split lines. - var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) { - var pos = 0, result = [], l = string.length - while (pos <= l) { - var nl = string.indexOf("\n", pos) - if (nl == -1) { nl = string.length } - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) - var rt = line.indexOf("\r") - if (rt != -1) { - result.push(line.slice(0, rt)) - pos += rt + 1 - } else { - result.push(line) - pos = nl + 1 - } - } - return result - } : function (string) { return string.split(/\r\n?|\n/); } - - var hasSelection = window.getSelection ? function (te) { - try { return te.selectionStart != te.selectionEnd } - catch(e) { return false } - } : function (te) { - var range - try {range = te.ownerDocument.selection.createRange()} - catch(e) {} - if (!range || range.parentElement() != te) { return false } - return range.compareEndPoints("StartToEnd", range) != 0 - } - - var hasCopyEvent = (function () { - var e = elt("div") - if ("oncopy" in e) { return true } - e.setAttribute("oncopy", "return;") - return typeof e.oncopy == "function" - })() - - var badZoomedRects = null - function hasBadZoomedRects(measure) { - if (badZoomedRects != null) { return badZoomedRects } - var node = removeChildrenAndAdd(measure, elt("span", "x")) - var normal = node.getBoundingClientRect() - var fromRange = range(node, 0, 1).getBoundingClientRect() - return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 - } - - var modes = {}; - var mimeModes = {}; - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - function defineMode(name, mode) { - if (arguments.length > 2) - { mode.dependencies = Array.prototype.slice.call(arguments, 2) } - modes[name] = mode - } - - function defineMIME(mime, spec) { - mimeModes[mime] = spec - } - - // Given a MIME type, a {name, ...options} config object, or a name - // string, return a mode config object. - function resolveMode(spec) { - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { - spec = mimeModes[spec] - } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name] - if (typeof found == "string") { found = {name: found} } - spec = createObj(found, spec) - spec.name = found.name - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { - return resolveMode("application/xml") - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { - return resolveMode("application/json") - } - if (typeof spec == "string") { return {name: spec} } - else { return spec || {name: "null"} } - } - - // Given a mode spec (anything that resolveMode accepts), find and - // initialize an actual mode object. - function getMode(options, spec) { - spec = resolveMode(spec) - var mfactory = modes[spec.name] - if (!mfactory) { return getMode(options, "text/plain") } - var modeObj = mfactory(options, spec) - if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name] - for (var prop in exts) { - if (!exts.hasOwnProperty(prop)) { continue } - if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] } - modeObj[prop] = exts[prop] - } - } - modeObj.name = spec.name - if (spec.helperType) { modeObj.helperType = spec.helperType } - if (spec.modeProps) { for (var prop$1 in spec.modeProps) - { modeObj[prop$1] = spec.modeProps[prop$1] } } - - return modeObj - } - - // This can be used to attach properties to mode objects from - // outside the actual mode definition. - var modeExtensions = {} - function extendMode(mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) - copyObj(properties, exts) - } - - function copyState(mode, state) { - if (state === true) { return state } - if (mode.copyState) { return mode.copyState(state) } - var nstate = {} - for (var n in state) { - var val = state[n] - if (val instanceof Array) { val = val.concat([]) } - nstate[n] = val - } - return nstate - } - - // Given a mode and a state (for that mode), find the inner mode and - // state at the position that the state refers to. - function innerMode(mode, state) { - var info - while (mode.innerMode) { - info = mode.innerMode(state) - if (!info || info.mode == mode) { break } - state = info.state - mode = info.mode - } - return info || {mode: mode, state: state} - } - - function startState(mode, a1, a2) { - return mode.startState ? mode.startState(a1, a2) : true - } - - // STRING STREAM - - // Fed to the mode parsers, provides helper functions to make - // parsers more succinct. - - var StringStream = function(string, tabSize, lineOracle) { - this.pos = this.start = 0 - this.string = string - this.tabSize = tabSize || 8 - this.lastColumnPos = this.lastColumnValue = 0 - this.lineStart = 0 - this.lineOracle = lineOracle - }; - - StringStream.prototype.eol = function () {return this.pos >= this.string.length}; - StringStream.prototype.sol = function () {return this.pos == this.lineStart}; - StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; - StringStream.prototype.next = function () { - if (this.pos < this.string.length) - { return this.string.charAt(this.pos++) } - }; - StringStream.prototype.eat = function (match) { - var ch = this.string.charAt(this.pos) - var ok - if (typeof match == "string") { ok = ch == match } - else { ok = ch && (match.test ? match.test(ch) : match(ch)) } - if (ok) {++this.pos; return ch} - }; - StringStream.prototype.eatWhile = function (match) { - var start = this.pos - while (this.eat(match)){} - return this.pos > start - }; - StringStream.prototype.eatSpace = function () { - var this$1 = this; - - var start = this.pos - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos } - return this.pos > start - }; - StringStream.prototype.skipToEnd = function () {this.pos = this.string.length}; - StringStream.prototype.skipTo = function (ch) { - var found = this.string.indexOf(ch, this.pos) - if (found > -1) {this.pos = found; return true} - }; - StringStream.prototype.backUp = function (n) {this.pos -= n}; - StringStream.prototype.column = function () { - if (this.lastColumnPos < this.start) { - this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue) - this.lastColumnPos = this.start - } - return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) - }; - StringStream.prototype.indentation = function () { - return countColumn(this.string, null, this.tabSize) - - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) - }; - StringStream.prototype.match = function (pattern, consume, caseInsensitive) { - if (typeof pattern == "string") { - var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; } - var substr = this.string.substr(this.pos, pattern.length) - if (cased(substr) == cased(pattern)) { - if (consume !== false) { this.pos += pattern.length } - return true - } - } else { - var match = this.string.slice(this.pos).match(pattern) - if (match && match.index > 0) { return null } - if (match && consume !== false) { this.pos += match[0].length } - return match - } - }; - StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; - StringStream.prototype.hideFirstChars = function (n, inner) { - this.lineStart += n - try { return inner() } - finally { this.lineStart -= n } - }; - StringStream.prototype.lookAhead = function (n) { - var oracle = this.lineOracle - return oracle && oracle.lookAhead(n) - }; - StringStream.prototype.baseToken = function () { - var oracle = this.lineOracle - return oracle && oracle.baseToken(this.pos) - }; - - var SavedContext = function(state, lookAhead) { - this.state = state - this.lookAhead = lookAhead - }; - - var Context = function(doc, state, line, lookAhead) { - this.state = state - this.doc = doc - this.line = line - this.maxLookAhead = lookAhead || 0 - this.baseTokens = null - this.baseTokenPos = 1 - }; - - Context.prototype.lookAhead = function (n) { - var line = this.doc.getLine(this.line + n) - if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n } - return line - }; - - Context.prototype.baseToken = function (n) { - var this$1 = this; - - if (!this.baseTokens) { return null } - while (this.baseTokens[this.baseTokenPos] <= n) - { this$1.baseTokenPos += 2 } - var type = this.baseTokens[this.baseTokenPos + 1] - return {type: type && type.replace(/( |^)overlay .*/, ""), - size: this.baseTokens[this.baseTokenPos] - n} - }; - - Context.prototype.nextLine = function () { - this.line++ - if (this.maxLookAhead > 0) { this.maxLookAhead-- } - }; - - Context.fromSaved = function (doc, saved, line) { - if (saved instanceof SavedContext) - { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) } - else - { return new Context(doc, copyState(doc.mode, saved), line) } - }; - - Context.prototype.save = function (copy) { - var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state - return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state - }; - - - // Compute a style array (an array starting with a mode generation - // -- for invalidation -- followed by pairs of end positions and - // style strings), which is used to highlight the tokens on the - // line. - function highlightLine(cm, line, context, forceToEnd) { - // A styles array always starts with a number identifying the - // mode/overlays that it is based on (for easy invalidation). - var st = [cm.state.modeGen], lineClasses = {} - // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); }, - lineClasses, forceToEnd) - var state = context.state - - // Run overlays, adjust style array. - var loop = function ( o ) { - context.baseTokens = st - var overlay = cm.state.overlays[o], i = 1, at = 0 - context.state = true - runMode(cm, line.text, overlay.mode, context, function (end, style) { - var start = i - // Ensure there's a token end at the current position, and that i points at it - while (at < end) { - var i_end = st[i] - if (i_end > end) - { st.splice(i, 1, end, st[i+1], i_end) } - i += 2 - at = Math.min(end, i_end) - } - if (!style) { return } - if (overlay.opaque) { - st.splice(start, i - start, end, "overlay " + style) - i = start + 2 - } else { - for (; start < i; start += 2) { - var cur = st[start+1] - st[start+1] = (cur ? cur + " " : "") + "overlay " + style - } - } - }, lineClasses) - context.state = state - context.baseTokens = null - context.baseTokenPos = 1 - }; - - for (var o = 0; o < cm.state.overlays.length; ++o) loop( o ); - - return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} - } - - function getLineStyles(cm, line, updateFrontier) { - if (!line.styles || line.styles[0] != cm.state.modeGen) { - var context = getContextBefore(cm, lineNo(line)) - var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state) - var result = highlightLine(cm, line, context) - if (resetState) { context.state = resetState } - line.stateAfter = context.save(!resetState) - line.styles = result.styles - if (result.classes) { line.styleClasses = result.classes } - else if (line.styleClasses) { line.styleClasses = null } - if (updateFrontier === cm.doc.highlightFrontier) - { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier) } - } - return line.styles - } - - function getContextBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display - if (!doc.mode.startState) { return new Context(doc, true, n) } - var start = findStartLine(cm, n, precise) - var saved = start > doc.first && getLine(doc, start - 1).stateAfter - var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start) - - doc.iter(start, n, function (line) { - processLine(cm, line.text, context) - var pos = context.line - line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null - context.nextLine() - }) - if (precise) { doc.modeFrontier = context.line } - return context - } - - // Lightweight form of highlight -- proceed over this line and - // update state, but don't save a style array. Used for lines that - // aren't currently visible. - function processLine(cm, text, context, startAt) { - var mode = cm.doc.mode - var stream = new StringStream(text, cm.options.tabSize, context) - stream.start = stream.pos = startAt || 0 - if (text == "") { callBlankLine(mode, context.state) } - while (!stream.eol()) { - readToken(mode, stream, context.state) - stream.start = stream.pos - } - } - - function callBlankLine(mode, state) { - if (mode.blankLine) { return mode.blankLine(state) } - if (!mode.innerMode) { return } - var inner = innerMode(mode, state) - if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) } - } - - function readToken(mode, stream, state, inner) { - for (var i = 0; i < 10; i++) { - if (inner) { inner[0] = innerMode(mode, state).mode } - var style = mode.token(stream, state) - if (stream.pos > stream.start) { return style } - } - throw new Error("Mode " + mode.name + " failed to advance stream.") - } - - var Token = function(stream, type, state) { - this.start = stream.start; this.end = stream.pos - this.string = stream.current() - this.type = type || null - this.state = state - }; - - // Utility for getTokenAt and getLineTokens - function takeToken(cm, pos, precise, asArray) { - var doc = cm.doc, mode = doc.mode, style - pos = clipPos(doc, pos) - var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise) - var stream = new StringStream(line.text, cm.options.tabSize, context), tokens - if (asArray) { tokens = [] } - while ((asArray || stream.pos < pos.ch) && !stream.eol()) { - stream.start = stream.pos - style = readToken(mode, stream, context.state) - if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))) } - } - return asArray ? tokens : new Token(stream, style, context.state) - } - - function extractLineClasses(type, output) { - if (type) { for (;;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) - if (!lineClass) { break } - type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length) - var prop = lineClass[1] ? "bgClass" : "textClass" - if (output[prop] == null) - { output[prop] = lineClass[2] } - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) - { output[prop] += " " + lineClass[2] } - } } - return type - } - - // Run the given mode's parser over a line, calling f for each token. - function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans - if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans } - var curStart = 0, curStyle = null - var stream = new StringStream(text, cm.options.tabSize, context), style - var inner = cm.options.addModeClass && [null] - if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses) } - while (!stream.eol()) { - if (stream.pos > cm.options.maxHighlightLength) { - flattenSpans = false - if (forceToEnd) { processLine(cm, text, context, stream.pos) } - stream.pos = text.length - style = null - } else { - style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses) - } - if (inner) { - var mName = inner[0].name - if (mName) { style = "m-" + (style ? mName + " " + style : mName) } - } - if (!flattenSpans || curStyle != style) { - while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 5000) - f(curStart, curStyle) - } - curStyle = style - } - stream.start = stream.pos - } - while (curStart < stream.pos) { - // Webkit seems to refuse to render text nodes longer than 57444 - // characters, and returns inaccurate measurements in nodes - // starting around 5000 chars. - var pos = Math.min(stream.pos, curStart + 5000) - f(pos, curStyle) - curStart = pos - } - } - - // Finds the line to start with when starting a parse. Tries to - // find a line with a stateAfter, so that it can start with a - // valid state. If that fails, it returns the line with the - // smallest indentation, which tends to need the least context to - // parse correctly. - function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) - for (var search = n; search > lim; --search) { - if (search <= doc.first) { return doc.first } - var line = getLine(doc, search - 1), after = line.stateAfter - if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier)) - { return search } - var indented = countColumn(line.text, null, cm.options.tabSize) - if (minline == null || minindent > indented) { - minline = search - 1 - minindent = indented - } - } - return minline - } - - function retreatFrontier(doc, n) { - doc.modeFrontier = Math.min(doc.modeFrontier, n) - if (doc.highlightFrontier < n - 10) { return } - var start = doc.first - for (var line = n - 1; line > start; line--) { - var saved = getLine(doc, line).stateAfter - // change is on 3 - // state on line 1 looked ahead 2 -- so saw 3 - // test 1 + 2 < 3 should cover this - if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) { - start = line + 1 - break - } - } - doc.highlightFrontier = Math.min(doc.highlightFrontier, start) - } - - // LINE DATA STRUCTURE - - // Line objects. These hold state related to a line, including - // highlighting info (the styles array). - var Line = function(text, markedSpans, estimateHeight) { - this.text = text - attachMarkedSpans(this, markedSpans) - this.height = estimateHeight ? estimateHeight(this) : 1 - }; - - Line.prototype.lineNo = function () { return lineNo(this) }; - eventMixin(Line) - - // Change the content (text, markers) of a line. Automatically - // invalidates cached information and tries to re-estimate the - // line's height. - function updateLine(line, text, markedSpans, estimateHeight) { - line.text = text - if (line.stateAfter) { line.stateAfter = null } - if (line.styles) { line.styles = null } - if (line.order != null) { line.order = null } - detachMarkedSpans(line) - attachMarkedSpans(line, markedSpans) - var estHeight = estimateHeight ? estimateHeight(line) : 1 - if (estHeight != line.height) { updateLineHeight(line, estHeight) } - } - - // Detach a line from the document tree and its markers. - function cleanUpLine(line) { - line.parent = null - detachMarkedSpans(line) - } - - // Convert a style as returned by a mode (either null, or a string - // containing one or more styles) to a CSS style. This is cached, - // and also looks for line-wide styles. - var styleToClassCache = {}; - var styleToClassCacheWithMode = {}; - function interpretTokenStyle(style, options) { - if (!style || /^\s*$/.test(style)) { return null } - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache - return cache[style] || - (cache[style] = style.replace(/\S+/g, "cm-$&")) - } - - // Render the DOM representation of the text of a line. Also builds - // up a 'line map', which points at the DOM nodes that represent - // specific stretches of text, and is used by the measuring code. - // The returned object contains the DOM node, this map, and - // information about line-wide styles that were set by the mode. - function buildLineContent(cm, lineView) { - // The padding-right forces the element to have a 'border', which - // is needed on Webkit to be able to get line-level bounding - // rectangles for it (in measureChar). - var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null) - var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, - col: 0, pos: 0, cm: cm, - trailingSpace: false, - splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} - lineView.measure = {} - - // Iterate over the logical lines that make up this visual line. - for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0) - builder.pos = 0 - builder.addToken = buildToken - // Optionally wire in some hacks into the token-rendering - // algorithm, to deal with browser quirks. - if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction))) - { builder.addToken = buildTokenBadBidi(builder.addToken, order) } - builder.map = [] - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) - insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)) - if (line.styleClasses) { - if (line.styleClasses.bgClass) - { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") } - if (line.styleClasses.textClass) - { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") } - } - - // Ensure at least a single node is present, for measuring. - if (builder.map.length == 0) - { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) } - - // Store the map and a cache object for the current logical line - if (i == 0) { - lineView.measure.map = builder.map - lineView.measure.cache = {} - } else { - ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) - ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}) - } - } - - // See issue #2901 - if (webkit) { - var last = builder.content.lastChild - if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) - { builder.content.className = "cm-tab-wrap-hack" } - } - - signal(cm, "renderLine", cm, lineView.line, builder.pre) - if (builder.pre.className) - { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") } - - return builder - } - - function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar") - token.title = "\\u" + ch.charCodeAt(0).toString(16) - token.setAttribute("aria-label", token.title) - return token - } - - // Build up the DOM representation for a single token, and add it to - // the line map. Takes care to render special characters separately. - function buildToken(builder, text, style, startStyle, endStyle, title, css) { - if (!text) { return } - var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text - var special = builder.cm.state.specialChars, mustWrap = false - var content - if (!special.test(text)) { - builder.col += text.length - content = document.createTextNode(displayText) - builder.map.push(builder.pos, builder.pos + text.length, content) - if (ie && ie_version < 9) { mustWrap = true } - builder.pos += text.length - } else { - content = document.createDocumentFragment() - var pos = 0 - while (true) { - special.lastIndex = pos - var m = special.exec(text) - var skipped = m ? m.index - pos : text.length - pos - if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)) - if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) } - else { content.appendChild(txt) } - builder.map.push(builder.pos, builder.pos + skipped, txt) - builder.col += skipped - builder.pos += skipped - } - if (!m) { break } - pos += skipped + 1 - var txt$1 = (void 0) - if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize - txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) - txt$1.setAttribute("role", "presentation") - txt$1.setAttribute("cm-text", "\t") - builder.col += tabWidth - } else if (m[0] == "\r" || m[0] == "\n") { - txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) - txt$1.setAttribute("cm-text", m[0]) - builder.col += 1 - } else { - txt$1 = builder.cm.options.specialCharPlaceholder(m[0]) - txt$1.setAttribute("cm-text", m[0]) - if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) } - else { content.appendChild(txt$1) } - builder.col += 1 - } - builder.map.push(builder.pos, builder.pos + 1, txt$1) - builder.pos++ - } - } - builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 - if (style || startStyle || endStyle || mustWrap || css) { - var fullStyle = style || "" - if (startStyle) { fullStyle += startStyle } - if (endStyle) { fullStyle += endStyle } - var token = elt("span", [content], fullStyle, css) - if (title) { token.title = title } - return builder.content.appendChild(token) - } - builder.content.appendChild(content) - } - - function splitSpaces(text, trailingBefore) { - if (text.length > 1 && !/ /.test(text)) { return text } - var spaceBefore = trailingBefore, result = "" - for (var i = 0; i < text.length; i++) { - var ch = text.charAt(i) - if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) - { ch = "\u00a0" } - result += ch - spaceBefore = ch == " " - } - return result - } - - // Work around nonsense dimensions being reported for stretches of - // right-to-left text. - function buildTokenBadBidi(inner, order) { - return function (builder, text, style, startStyle, endStyle, title, css) { - style = style ? style + " cm-force-border" : "cm-force-border" - var start = builder.pos, end = start + text.length - for (;;) { - // Find the part that overlaps with the start of this text - var part = (void 0) - for (var i = 0; i < order.length; i++) { - part = order[i] - if (part.to > start && part.from <= start) { break } - } - if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) } - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css) - startStyle = null - text = text.slice(part.to - start) - start = part.to - } - } - } - - function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode - if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) } - if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { - if (!widget) - { widget = builder.content.appendChild(document.createElement("span")) } - widget.setAttribute("cm-marker", marker.id) - } - if (widget) { - builder.cm.display.input.setUneditable(widget) - builder.content.appendChild(widget) - } - builder.pos += size - builder.trailingSpace = false - } - - // Outputs a number of spans to make up a line, taking highlighting - // and marked text into account. - function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0 - if (!spans) { - for (var i$1 = 1; i$1 < styles.length; i$1+=2) - { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) } - return - } - - var len = allText.length, pos = 0, i = 1, text = "", style, css - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed - for (;;) { - if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = title = css = "" - collapsed = null; nextChange = Infinity - var foundBookmarks = [], endStyles = (void 0) - for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker - if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { - foundBookmarks.push(m) - } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { - if (sp.to != null && sp.to != pos && nextChange > sp.to) { - nextChange = sp.to - spanEndStyle = "" - } - if (m.className) { spanStyle += " " + m.className } - if (m.css) { css = (css ? css + ";" : "") + m.css } - if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle } - if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) } - if (m.title && !title) { title = m.title } - if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) - { collapsed = sp } - } else if (sp.from > pos && nextChange > sp.from) { - nextChange = sp.from - } - } - if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2) - { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } } - - if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2) - { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } } - if (collapsed && (collapsed.from || 0) == pos) { - buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, - collapsed.marker, collapsed.from == null) - if (collapsed.to == null) { return } - if (collapsed.to == pos) { collapsed = false } - } - } - if (pos >= len) { break } - - var upto = Math.min(len, nextChange) - while (true) { - if (text) { - var end = pos + text.length - if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text - builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css) - } - if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} - pos = end - spanStartStyle = "" - } - text = allText.slice(at, at = styles[i++]) - style = interpretTokenStyle(styles[i++], builder.cm.options) - } - } - } - - - // These objects are used to represent the visible (currently drawn) - // part of the document. A LineView may correspond to multiple - // logical lines, if those are connected by collapsed ranges. - function LineView(doc, line, lineN) { - // The starting line - this.line = line - // Continuing lines, if any - this.rest = visualLineContinued(line) - // Number of logical lines in this visual line - this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1 - this.node = this.text = null - this.hidden = lineIsHidden(doc, line) - } - - // Create a range of LineView objects for the given lines. - function buildViewArray(cm, from, to) { - var array = [], nextPos - for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos) - nextPos = pos + view.size - array.push(view) - } - return array - } - - var operationGroup = null - - function pushOperation(op) { - if (operationGroup) { - operationGroup.ops.push(op) - } else { - op.ownsGroup = operationGroup = { - ops: [op], - delayedCallbacks: [] - } - } - } - - function fireCallbacksForOps(group) { - // Calls delayed callbacks and cursorActivity handlers until no - // new ones appear - var callbacks = group.delayedCallbacks, i = 0 - do { - for (; i < callbacks.length; i++) - { callbacks[i].call(null) } - for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j] - if (op.cursorActivityHandlers) - { while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } } - } - } while (i < callbacks.length) - } - - function finishOperation(op, endCb) { - var group = op.ownsGroup - if (!group) { return } - - try { fireCallbacksForOps(group) } - finally { - operationGroup = null - endCb(group) - } - } - - var orphanDelayedCallbacks = null - - // Often, we want to signal events at a point where we are in the - // middle of some work, but don't want the handler to start calling - // other methods on the editor, which might be in an inconsistent - // state or simply not expect any other events to happen. - // signalLater looks whether there are any handlers, and schedules - // them to be executed when the last operation ends, or, if no - // operation is active, when a timeout fires. - function signalLater(emitter, type /*, values...*/) { - var arr = getHandlers(emitter, type) - if (!arr.length) { return } - var args = Array.prototype.slice.call(arguments, 2), list - if (operationGroup) { - list = operationGroup.delayedCallbacks - } else if (orphanDelayedCallbacks) { - list = orphanDelayedCallbacks - } else { - list = orphanDelayedCallbacks = [] - setTimeout(fireOrphanDelayed, 0) - } - var loop = function ( i ) { - list.push(function () { return arr[i].apply(null, args); }) - }; - - for (var i = 0; i < arr.length; ++i) - loop( i ); - } - - function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks - orphanDelayedCallbacks = null - for (var i = 0; i < delayed.length; ++i) { delayed[i]() } - } - - // When an aspect of a line changes, a string is added to - // lineView.changes. This updates the relevant part of the line's - // DOM structure. - function updateLineForChanges(cm, lineView, lineN, dims) { - for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j] - if (type == "text") { updateLineText(cm, lineView) } - else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) } - else if (type == "class") { updateLineClasses(cm, lineView) } - else if (type == "widget") { updateLineWidgets(cm, lineView, dims) } - } - lineView.changes = null - } - - // Lines with gutter elements, widgets or a background class need to - // be wrapped, and have the extra elements added to the wrapper div - function ensureLineWrapped(lineView) { - if (lineView.node == lineView.text) { - lineView.node = elt("div", null, null, "position: relative") - if (lineView.text.parentNode) - { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) } - lineView.node.appendChild(lineView.text) - if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 } - } - return lineView.node - } - - function updateLineBackground(cm, lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass - if (cls) { cls += " CodeMirror-linebackground" } - if (lineView.background) { - if (cls) { lineView.background.className = cls } - else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null } - } else if (cls) { - var wrap = ensureLineWrapped(lineView) - lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild) - cm.display.input.setUneditable(lineView.background) - } - } - - // Wrapper around buildLineContent which will reuse the structure - // in display.externalMeasured when possible. - function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured - if (ext && ext.line == lineView.line) { - cm.display.externalMeasured = null - lineView.measure = ext.measure - return ext.built - } - return buildLineContent(cm, lineView) - } - - // Redraw the line's text. Interacts with the background and text - // classes because the mode may output tokens that influence these - // classes. - function updateLineText(cm, lineView) { - var cls = lineView.text.className - var built = getLineContent(cm, lineView) - if (lineView.text == lineView.node) { lineView.node = built.pre } - lineView.text.parentNode.replaceChild(built.pre, lineView.text) - lineView.text = built.pre - if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { - lineView.bgClass = built.bgClass - lineView.textClass = built.textClass - updateLineClasses(cm, lineView) - } else if (cls) { - lineView.text.className = cls - } - } - - function updateLineClasses(cm, lineView) { - updateLineBackground(cm, lineView) - if (lineView.line.wrapClass) - { ensureLineWrapped(lineView).className = lineView.line.wrapClass } - else if (lineView.node != lineView.text) - { lineView.node.className = "" } - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass - lineView.text.className = textClass || "" - } - - function updateLineGutter(cm, lineView, lineN, dims) { - if (lineView.gutter) { - lineView.node.removeChild(lineView.gutter) - lineView.gutter = null - } - if (lineView.gutterBackground) { - lineView.node.removeChild(lineView.gutterBackground) - lineView.gutterBackground = null - } - if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView) - lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, - ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px")) - cm.display.input.setUneditable(lineView.gutterBackground) - wrap.insertBefore(lineView.gutterBackground, lineView.text) - } - var markers = lineView.line.gutterMarkers - if (cm.options.lineNumbers || markers) { - var wrap$1 = ensureLineWrapped(lineView) - var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")) - cm.display.input.setUneditable(gutterWrap) - wrap$1.insertBefore(gutterWrap, lineView.text) - if (lineView.line.gutterClass) - { gutterWrap.className += " " + lineView.line.gutterClass } - if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) - { lineView.lineNumber = gutterWrap.appendChild( - elt("div", lineNumberFor(cm.options, lineN), - "CodeMirror-linenumber CodeMirror-gutter-elt", - ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) } - if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) { - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] - if (found) - { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", - ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) } - } } - } - } - - function updateLineWidgets(cm, lineView, dims) { - if (lineView.alignable) { lineView.alignable = null } - for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { - next = node.nextSibling - if (node.className == "CodeMirror-linewidget") - { lineView.node.removeChild(node) } - } - insertLineWidgets(cm, lineView, dims) - } - - // Build a line's DOM representation from scratch - function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView) - lineView.text = lineView.node = built.pre - if (built.bgClass) { lineView.bgClass = built.bgClass } - if (built.textClass) { lineView.textClass = built.textClass } - - updateLineClasses(cm, lineView) - updateLineGutter(cm, lineView, lineN, dims) - insertLineWidgets(cm, lineView, dims) - return lineView.node - } - - // A lineView may contain multiple logical lines (when merged by - // collapsed spans). The widgets for all of them need to be drawn. - function insertLineWidgets(cm, lineView, dims) { - insertLineWidgetsFor(cm, lineView.line, lineView, dims, true) - if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) - { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } } - } - - function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { - if (!line.widgets) { return } - var wrap = ensureLineWrapped(lineView) - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") - if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") } - positionLineWidget(widget, node, lineView, dims) - cm.display.input.setUneditable(node) - if (allowAbove && widget.above) - { wrap.insertBefore(node, lineView.gutter || lineView.text) } - else - { wrap.appendChild(node) } - signalLater(widget, "redraw") - } - } - - function positionLineWidget(widget, node, lineView, dims) { - if (widget.noHScroll) { - ;(lineView.alignable || (lineView.alignable = [])).push(node) - var width = dims.wrapperWidth - node.style.left = dims.fixedPos + "px" - if (!widget.coverGutter) { - width -= dims.gutterTotalWidth - node.style.paddingLeft = dims.gutterTotalWidth + "px" - } - node.style.width = width + "px" - } - if (widget.coverGutter) { - node.style.zIndex = 5 - node.style.position = "relative" - if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" } - } - } - - function widgetHeight(widget) { - if (widget.height != null) { return widget.height } - var cm = widget.doc.cm - if (!cm) { return 0 } - if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;" - if (widget.coverGutter) - { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" } - if (widget.noHScroll) - { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" } - removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)) - } - return widget.height = widget.node.parentNode.offsetHeight - } - - // Return true when the given mouse event happened in a widget - function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { - if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || - (n.parentNode == display.sizer && n != display.mover)) - { return true } - } - } - - // POSITION MEASUREMENT - - function paddingTop(display) {return display.lineSpace.offsetTop} - function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} - function paddingH(display) { - if (display.cachedPaddingH) { return display.cachedPaddingH } - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")) - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle - var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} - if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data } - return data - } - - function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } - function displayWidth(cm) { - return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth - } - function displayHeight(cm) { - return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight - } - - // Ensure the lineView.wrapping.heights array is populated. This is - // an array of bottom offsets for the lines that make up a drawn - // line. When lineWrapping is on, there might be more than one - // height. - function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping - var curWidth = wrapping && displayWidth(cm) - if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = [] - if (wrapping) { - lineView.measure.width = curWidth - var rects = lineView.text.firstChild.getClientRects() - for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1] - if (Math.abs(cur.bottom - next.bottom) > 2) - { heights.push((cur.bottom + next.top) / 2 - rect.top) } - } - } - heights.push(rect.bottom - rect.top) - } - } - - // Find a line map (mapping character offsets to text nodes) and a - // measurement cache for the given line number. (A line view might - // contain multiple lines when collapsed ranges are present.) - function mapFromLineView(lineView, line, lineN) { - if (lineView.line == line) - { return {map: lineView.measure.map, cache: lineView.measure.cache} } - for (var i = 0; i < lineView.rest.length; i++) - { if (lineView.rest[i] == line) - { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } - for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) - { if (lineNo(lineView.rest[i$1]) > lineN) - { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } - } - - // Render a line into the hidden node display.externalMeasured. Used - // when measurement is needed for a line that's not in the viewport. - function updateExternalMeasurement(cm, line) { - line = visualLine(line) - var lineN = lineNo(line) - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) - view.lineN = lineN - var built = view.built = buildLineContent(cm, view) - view.text = built.pre - removeChildrenAndAdd(cm.display.lineMeasure, built.pre) - return view - } - - // Get a {top, bottom, left, right} box (in line-local coordinates) - // for a given character. - function measureChar(cm, line, ch, bias) { - return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) - } - - // Find a line view that corresponds to the given line number. - function findViewForLine(cm, lineN) { - if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) - { return cm.display.view[findViewIndex(cm, lineN)] } - var ext = cm.display.externalMeasured - if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) - { return ext } - } - - // Measurement can be split in two steps, the set-up work that - // applies to the whole line, and the measurement of the actual - // character. Functions like coordsChar, that need to do a lot of - // measurements in a row, can thus ensure that the set-up work is - // only done once. - function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line) - var view = findViewForLine(cm, lineN) - if (view && !view.text) { - view = null - } else if (view && view.changes) { - updateLineForChanges(cm, view, lineN, getDimensions(cm)) - cm.curOp.forceUpdate = true - } - if (!view) - { view = updateExternalMeasurement(cm, line) } - - var info = mapFromLineView(view, line, lineN) - return { - line: line, view: view, rect: null, - map: info.map, cache: info.cache, before: info.before, - hasHeights: false - } - } - - // Given a prepared measurement object, measures the position of an - // actual character (or fetches it from the cache). - function measureCharPrepared(cm, prepared, ch, bias, varHeight) { - if (prepared.before) { ch = -1 } - var key = ch + (bias || ""), found - if (prepared.cache.hasOwnProperty(key)) { - found = prepared.cache[key] - } else { - if (!prepared.rect) - { prepared.rect = prepared.view.text.getBoundingClientRect() } - if (!prepared.hasHeights) { - ensureLineHeights(cm, prepared.view, prepared.rect) - prepared.hasHeights = true - } - found = measureCharInner(cm, prepared, ch, bias) - if (!found.bogus) { prepared.cache[key] = found } - } - return {left: found.left, right: found.right, - top: varHeight ? found.rtop : found.top, - bottom: varHeight ? found.rbottom : found.bottom} - } - - var nullRect = {left: 0, right: 0, top: 0, bottom: 0} - - function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse, mStart, mEnd - // First, search the line map for the text node corresponding to, - // or closest to, the target character. - for (var i = 0; i < map.length; i += 3) { - mStart = map[i] - mEnd = map[i + 1] - if (ch < mStart) { - start = 0; end = 1 - collapse = "left" - } else if (ch < mEnd) { - start = ch - mStart - end = start + 1 - } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { - end = mEnd - mStart - start = end - 1 - if (ch >= mEnd) { collapse = "right" } - } - if (start != null) { - node = map[i + 2] - if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) - { collapse = bias } - if (bias == "left" && start == 0) - { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { - node = map[(i -= 3) + 2] - collapse = "left" - } } - if (bias == "right" && start == mEnd - mStart) - { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { - node = map[(i += 3) + 2] - collapse = "right" - } } - break - } - } - return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} - } - - function getUsefulRect(rects, bias) { - var rect = nullRect - if (bias == "left") { for (var i = 0; i < rects.length; i++) { - if ((rect = rects[i]).left != rect.right) { break } - } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) { - if ((rect = rects[i$1]).left != rect.right) { break } - } } - return rect - } - - function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias) - var node = place.node, start = place.start, end = place.end, collapse = place.collapse - - var rect - if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. - for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned - while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start } - while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end } - if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) - { rect = node.parentNode.getBoundingClientRect() } - else - { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) } - if (rect.left || rect.right || start == 0) { break } - end = start - start = start - 1 - collapse = "right" - } - if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) } - } else { // If it is a widget, simply get the box for the whole widget. - if (start > 0) { collapse = bias = "right" } - var rects - if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) - { rect = rects[bias == "right" ? rects.length - 1 : 0] } - else - { rect = node.getBoundingClientRect() } - } - if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0] - if (rSpan) - { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} } - else - { rect = nullRect } - } - - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top - var mid = (rtop + rbot) / 2 - var heights = prepared.view.measure.heights - var i = 0 - for (; i < heights.length - 1; i++) - { if (mid < heights[i]) { break } } - var top = i ? heights[i - 1] : 0, bot = heights[i] - var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, - right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, - top: top, bottom: bot} - if (!rect.left && !rect.right) { result.bogus = true } - if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot } - - return result - } - - // Work around problem with bounding client rects on ranges being - // returned incorrectly when zoomed on IE10 and below. - function maybeUpdateRectForZooming(measure, rect) { - if (!window.screen || screen.logicalXDPI == null || - screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) - { return rect } - var scaleX = screen.logicalXDPI / screen.deviceXDPI - var scaleY = screen.logicalYDPI / screen.deviceYDPI - return {left: rect.left * scaleX, right: rect.right * scaleX, - top: rect.top * scaleY, bottom: rect.bottom * scaleY} - } - - function clearLineMeasurementCacheFor(lineView) { - if (lineView.measure) { - lineView.measure.cache = {} - lineView.measure.heights = null - if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) - { lineView.measure.caches[i] = {} } } - } - } - - function clearLineMeasurementCache(cm) { - cm.display.externalMeasure = null - removeChildren(cm.display.lineMeasure) - for (var i = 0; i < cm.display.view.length; i++) - { clearLineMeasurementCacheFor(cm.display.view[i]) } - } - - function clearCaches(cm) { - clearLineMeasurementCache(cm) - cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null - if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true } - cm.display.lineNumChars = null - } - - function pageScrollX() { - // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206 - // which causes page_Offset and bounding client rects to use - // different reference viewports and invalidate our calculations. - if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) } - return window.pageXOffset || (document.documentElement || document.body).scrollLeft - } - function pageScrollY() { - if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) } - return window.pageYOffset || (document.documentElement || document.body).scrollTop - } - - function widgetTopHeight(lineObj) { - var height = 0 - if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) - { height += widgetHeight(lineObj.widgets[i]) } } } - return height - } - - // Converts a {top, bottom, left, right} box from line-local - // coordinates into another coordinate system. Context may be one of - // "line", "div" (display.lineDiv), "local"./null (editor), "window", - // or "page". - function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { - if (!includeWidgets) { - var height = widgetTopHeight(lineObj) - rect.top += height; rect.bottom += height - } - if (context == "line") { return rect } - if (!context) { context = "local" } - var yOff = heightAtLine(lineObj) - if (context == "local") { yOff += paddingTop(cm.display) } - else { yOff -= cm.display.viewOffset } - if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect() - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()) - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) - rect.left += xOff; rect.right += xOff - } - rect.top += yOff; rect.bottom += yOff - return rect - } - - // Coverts a box from "div" coords to another coordinate system. - // Context may be "window", "page", "div", or "local"./null. - function fromCoordSystem(cm, coords, context) { - if (context == "div") { return coords } - var left = coords.left, top = coords.top - // First move into "page" coordinate system - if (context == "page") { - left -= pageScrollX() - top -= pageScrollY() - } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect() - left += localBox.left - top += localBox.top - } - - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() - return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} - } - - function charCoords(cm, pos, context, lineObj, bias) { - if (!lineObj) { lineObj = getLine(cm.doc, pos.line) } - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) - } - - // Returns a box for a given cursor position, which may have an - // 'other' property containing the position of the secondary cursor - // on a bidi boundary. - // A cursor Pos(line, char, "before") is on the same visual line as `char - 1` - // and after `char - 1` in writing order of `char - 1` - // A cursor Pos(line, char, "after") is on the same visual line as `char` - // and before `char` in writing order of `char` - // Examples (upper-case letters are RTL, lower-case are LTR): - // Pos(0, 1, ...) - // before after - // ab a|b a|b - // aB a|B aB| - // Ab |Ab A|b - // AB B|A B|A - // Every position after the last character on a line is considered to stick - // to the last character on the line. - function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { - lineObj = lineObj || getLine(cm.doc, pos.line) - if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) } - function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) - if (right) { m.left = m.right; } else { m.right = m.left } - return intoCoordSystem(cm, lineObj, m, context) - } - var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky - if (ch >= lineObj.text.length) { - ch = lineObj.text.length - sticky = "before" - } else if (ch <= 0) { - ch = 0 - sticky = "after" - } - if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") } - - function getBidi(ch, partPos, invert) { - var part = order[partPos], right = part.level == 1 - return get(invert ? ch - 1 : ch, right != invert) - } - var partPos = getBidiPartAt(order, ch, sticky) - var other = bidiOther - var val = getBidi(ch, partPos, sticky == "before") - if (other != null) { val.other = getBidi(ch, other, sticky != "before") } - return val - } - - // Used to cheaply estimate the coordinates for a position. Used for - // intermediate scroll updates. - function estimateCoords(cm, pos) { - var left = 0 - pos = clipPos(cm.doc, pos) - if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch } - var lineObj = getLine(cm.doc, pos.line) - var top = heightAtLine(lineObj) + paddingTop(cm.display) - return {left: left, right: left, top: top, bottom: top + lineObj.height} - } - - // Positions returned by coordsChar contain some extra information. - // xRel is the relative x position of the input coordinates compared - // to the found position (so xRel > 0 means the coordinates are to - // the right of the character position, for example). When outside - // is true, that means the coordinates lie outside the line's - // vertical range. - function PosWithInfo(line, ch, sticky, outside, xRel) { - var pos = Pos(line, ch, sticky) - pos.xRel = xRel - if (outside) { pos.outside = true } - return pos - } - - // Compute the character position closest to the given coordinates. - // Input must be lineSpace-local ("div" coordinate system). - function coordsChar(cm, x, y) { - var doc = cm.doc - y += cm.display.viewOffset - if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) } - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 - if (lineN > last) - { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) } - if (x < 0) { x = 0 } - - var lineObj = getLine(doc, lineN) - for (;;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y) - var merged = collapsedSpanAtEnd(lineObj) - var mergedPos = merged && merged.find(0, true) - if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - { lineN = lineNo(lineObj = mergedPos.to.line) } - else - { return found } - } - } - - function wrappedLineExtent(cm, lineObj, preparedMeasure, y) { - y -= widgetTopHeight(lineObj) - var end = lineObj.text.length - var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0) - end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end) - return {begin: begin, end: end} - } - - function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) { - if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) } - var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top - return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop) - } - - // Returns true if the given side of a box is after the given - // coordinates, in top-to-bottom, left-to-right order. - function boxIsAfter(box, x, y, left) { - return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x - } - - function coordsCharInner(cm, lineObj, lineNo, x, y) { - // Move y into line-local coordinate space - y -= heightAtLine(lineObj) - var preparedMeasure = prepareMeasureForLine(cm, lineObj) - // When directly calling `measureCharPrepared`, we have to adjust - // for the widgets at this line. - var widgetHeight = widgetTopHeight(lineObj) - var begin = 0, end = lineObj.text.length, ltr = true - - var order = getOrder(lineObj, cm.doc.direction) - // If the line isn't plain left-to-right text, first figure out - // which bidi section the coordinates fall into. - if (order) { - var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) - (cm, lineObj, lineNo, preparedMeasure, order, x, y) - ltr = part.level != 1 - // The awkward -1 offsets are needed because findFirst (called - // on these below) will treat its first bound as inclusive, - // second as exclusive, but we want to actually address the - // characters in the part's range - begin = ltr ? part.from : part.to - 1 - end = ltr ? part.to : part.from - 1 - } - - // A binary search to find the first character whose bounding box - // starts after the coordinates. If we run across any whose box wrap - // the coordinates, store that. - var chAround = null, boxAround = null - var ch = findFirst(function (ch) { - var box = measureCharPrepared(cm, preparedMeasure, ch) - box.top += widgetHeight; box.bottom += widgetHeight - if (!boxIsAfter(box, x, y, false)) { return false } - if (box.top <= y && box.left <= x) { - chAround = ch - boxAround = box - } - return true - }, begin, end) - - var baseX, sticky, outside = false - // If a box around the coordinates was found, use that - if (boxAround) { - // Distinguish coordinates nearer to the left or right side of the box - var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr - ch = chAround + (atStart ? 0 : 1) - sticky = atStart ? "after" : "before" - baseX = atLeft ? boxAround.left : boxAround.right - } else { - // (Adjust for extended bound, if necessary.) - if (!ltr && (ch == end || ch == begin)) { ch++ } - // To determine which side to associate with, get the box to the - // left of the character and compare it's vertical position to the - // coordinates - sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : - (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? - "after" : "before" - // Now get accurate coordinates for this place, in order to get a - // base X position - var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure) - baseX = coords.left - outside = y < coords.top || y >= coords.bottom - } - - ch = skipExtendingChars(lineObj.text, ch, 1) - return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) - } - - function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { - // Bidi parts are sorted left-to-right, and in a non-line-wrapping - // situation, we can take this ordering to correspond to the visual - // ordering. This finds the first part whose end is after the given - // coordinates. - var index = findFirst(function (i) { - var part = order[i], ltr = part.level != 1 - return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), - "line", lineObj, preparedMeasure), x, y, true) - }, 0, order.length - 1) - var part = order[index] - // If this isn't the first part, the part's start is also after - // the coordinates, and the coordinates aren't on the same line as - // that start, move one part back. - if (index > 0) { - var ltr = part.level != 1 - var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), - "line", lineObj, preparedMeasure) - if (boxIsAfter(start, x, y, true) && start.top > y) - { part = order[index - 1] } - } - return part - } - - function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) { - // In a wrapped line, rtl text on wrapping boundaries can do things - // that don't correspond to the ordering in our `order` array at - // all, so a binary search doesn't work, and we want to return a - // part that only spans one line so that the binary search in - // coordsCharInner is safe. As such, we first find the extent of the - // wrapped line, and then do a flat search in which we discard any - // spans that aren't on the line. - var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y); - var begin = ref.begin; - var end = ref.end; - if (/\s/.test(lineObj.text.charAt(end - 1))) { end-- } - var part = null, closestDist = null - for (var i = 0; i < order.length; i++) { - var p = order[i] - if (p.from >= end || p.to <= begin) { continue } - var ltr = p.level != 1 - var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right - // Weigh against spans ending before this, so that they are only - // picked if nothing ends after - var dist = endX < x ? x - endX + 1e9 : endX - x - if (!part || closestDist > dist) { - part = p - closestDist = dist - } - } - if (!part) { part = order[order.length - 1] } - // Clip the part to the wrapped line. - if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} } - if (part.to > end) { part = {from: part.from, to: end, level: part.level} } - return part - } - - var measureText - // Compute the default text height. - function textHeight(display) { - if (display.cachedTextHeight != null) { return display.cachedTextHeight } - if (measureText == null) { - measureText = elt("pre") - // Measure a bunch of lines, for browsers that compute - // fractional heights. - for (var i = 0; i < 49; ++i) { - measureText.appendChild(document.createTextNode("x")) - measureText.appendChild(elt("br")) - } - measureText.appendChild(document.createTextNode("x")) - } - removeChildrenAndAdd(display.measure, measureText) - var height = measureText.offsetHeight / 50 - if (height > 3) { display.cachedTextHeight = height } - removeChildren(display.measure) - return height || 1 - } - - // Compute the default character width. - function charWidth(display) { - if (display.cachedCharWidth != null) { return display.cachedCharWidth } - var anchor = elt("span", "xxxxxxxxxx") - var pre = elt("pre", [anchor]) - removeChildrenAndAdd(display.measure, pre) - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 - if (width > 2) { display.cachedCharWidth = width } - return width || 10 - } - - // Do a bulk-read of the DOM positions and sizes needed to draw the - // view, so that we don't interleave reading and writing to the DOM. - function getDimensions(cm) { - var d = cm.display, left = {}, width = {} - var gutterLeft = d.gutters.clientLeft - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { - left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft - width[cm.options.gutters[i]] = n.clientWidth - } - return {fixedPos: compensateForHScroll(d), - gutterTotalWidth: d.gutters.offsetWidth, - gutterLeft: left, - gutterWidth: width, - wrapperWidth: d.wrapper.clientWidth} - } - - // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, - // but using getBoundingClientRect to get a sub-pixel-accurate - // result. - function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left - } - - // Returns a function that estimates the height of a line, to use as - // first approximation until the line becomes visible (and is thus - // properly measurable). - function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) - return function (line) { - if (lineIsHidden(cm.doc, line)) { return 0 } - - var widgetsHeight = 0 - if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) { - if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height } - } } - - if (wrapping) - { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th } - else - { return widgetsHeight + th } - } - } - - function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm) - doc.iter(function (line) { - var estHeight = est(line) - if (estHeight != line.height) { updateLineHeight(line, estHeight) } - }) - } - - // Given a mouse event, find the corresponding position. If liberal - // is false, it checks whether a gutter or scrollbar was clicked, - // and returns null if it was. forRect is used by rectangular - // selections, and tries to estimate a character position even for - // coordinates beyond the right of the text. - function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display - if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null } - - var x, y, space = display.lineSpace.getBoundingClientRect() - // Fails unpredictably on IE[67] when mouse is dragged around quickly. - try { x = e.clientX - space.left; y = e.clientY - space.top } - catch (e) { return null } - var coords = coordsChar(cm, x, y), line - if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length - coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)) - } - return coords - } - - // Find the view element corresponding to a given line. Return null - // when the line isn't visible. - function findViewIndex(cm, n) { - if (n >= cm.display.viewTo) { return null } - n -= cm.display.viewFrom - if (n < 0) { return null } - var view = cm.display.view - for (var i = 0; i < view.length; i++) { - n -= view[i].size - if (n < 0) { return i } - } - } - - function updateSelection(cm) { - cm.display.input.showSelection(cm.display.input.prepareSelection()) - } - - function prepareSelection(cm, primary) { - if ( primary === void 0 ) primary = true; - - var doc = cm.doc, result = {} - var curFragment = result.cursors = document.createDocumentFragment() - var selFragment = result.selection = document.createDocumentFragment() - - for (var i = 0; i < doc.sel.ranges.length; i++) { - if (!primary && i == doc.sel.primIndex) { continue } - var range = doc.sel.ranges[i] - if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } - var collapsed = range.empty() - if (collapsed || cm.options.showCursorWhenSelecting) - { drawSelectionCursor(cm, range.head, curFragment) } - if (!collapsed) - { drawSelectionRange(cm, range, selFragment) } - } - return result - } - - // Draws a cursor for the given range - function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) - - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) - cursor.style.left = pos.left + "px" - cursor.style.top = pos.top + "px" - cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" - - if (pos.other) { - // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) - otherCursor.style.display = "" - otherCursor.style.left = pos.other.left + "px" - otherCursor.style.top = pos.other.top + "px" - otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px" - } - } - - function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } - - // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc - var fragment = document.createDocumentFragment() - var padding = paddingH(cm.display), leftSide = padding.left - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right - var docLTR = doc.direction == "ltr" - - function add(left, top, width, bottom) { - if (top < 0) { top = 0 } - top = Math.round(top) - bottom = Math.round(bottom) - fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px"))) - } - - function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line) - var lineLen = lineObj.text.length - var start, end - function coords(ch, bias) { - return charCoords(cm, Pos(line, ch), "div", lineObj, bias) - } - - function wrapX(pos, dir, side) { - var extent = wrappedLineExtentChar(cm, lineObj, null, pos) - var prop = (dir == "ltr") == (side == "after") ? "left" : "right" - var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1) - return coords(ch, prop)[prop] - } - - var order = getOrder(lineObj, doc.direction) - iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) { - var ltr = dir == "ltr" - var fromPos = coords(from, ltr ? "left" : "right") - var toPos = coords(to - 1, ltr ? "right" : "left") - - var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen - var first = i == 0, last = !order || i == order.length - 1 - if (toPos.top - fromPos.top <= 3) { // Single line - var openLeft = (docLTR ? openStart : openEnd) && first - var openRight = (docLTR ? openEnd : openStart) && last - var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left - var right = openRight ? rightSide : (ltr ? toPos : fromPos).right - add(left, fromPos.top, right - left, fromPos.bottom) - } else { // Multiple lines - var topLeft, topRight, botLeft, botRight - if (ltr) { - topLeft = docLTR && openStart && first ? leftSide : fromPos.left - topRight = docLTR ? rightSide : wrapX(from, dir, "before") - botLeft = docLTR ? leftSide : wrapX(to, dir, "after") - botRight = docLTR && openEnd && last ? rightSide : toPos.right - } else { - topLeft = !docLTR ? leftSide : wrapX(from, dir, "before") - topRight = !docLTR && openStart && first ? rightSide : fromPos.right - botLeft = !docLTR && openEnd && last ? leftSide : toPos.left - botRight = !docLTR ? rightSide : wrapX(to, dir, "after") - } - add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom) - if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) } - add(botLeft, toPos.top, botRight - botLeft, toPos.bottom) - } - - if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos } - if (cmpCoords(toPos, start) < 0) { start = toPos } - if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos } - if (cmpCoords(toPos, end) < 0) { end = toPos } - }) - return {start: start, end: end} - } - - var sFrom = range.from(), sTo = range.to() - if (sFrom.line == sTo.line) { - drawForLine(sFrom.line, sFrom.ch, sTo.ch) - } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) - var singleVLine = visualLine(fromLine) == visualLine(toLine) - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start - if (singleVLine) { - if (leftEnd.top < rightStart.top - 2) { - add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) - add(leftSide, rightStart.top, rightStart.left, rightStart.bottom) - } else { - add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom) - } - } - if (leftEnd.bottom < rightStart.top) - { add(leftSide, leftEnd.bottom, null, rightStart.top) } - } - - output.appendChild(fragment) - } - - // Cursor-blinking - function restartBlink(cm) { - if (!cm.state.focused) { return } - var display = cm.display - clearInterval(display.blinker) - var on = true - display.cursorDiv.style.visibility = "" - if (cm.options.cursorBlinkRate > 0) - { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, - cm.options.cursorBlinkRate) } - else if (cm.options.cursorBlinkRate < 0) - { display.cursorDiv.style.visibility = "hidden" } - } - - function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } - } - - function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true - setTimeout(function () { if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false - onBlur(cm) - } }, 100) - } - - function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false } - - if (cm.options.readOnly == "nocursor") { return } - if (!cm.state.focused) { - signal(cm, "focus", cm, e) - cm.state.focused = true - addClass(cm.display.wrapper, "CodeMirror-focused") - // This test prevents this from firing when a context - // menu is closed (since the input reset would kill the - // select-all detection hack) - if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { - cm.display.input.reset() - if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730 - } - cm.display.input.receivedFocus() - } - restartBlink(cm) - } - function onBlur(cm, e) { - if (cm.state.delayingBlurEvent) { return } - - if (cm.state.focused) { - signal(cm, "blur", cm, e) - cm.state.focused = false - rmClass(cm.display.wrapper, "CodeMirror-focused") - } - clearInterval(cm.display.blinker) - setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150) - } - - // Read the actual heights of the rendered lines, and update their - // stored heights to match. - function updateHeightsInViewport(cm) { - var display = cm.display - var prevBottom = display.lineDiv.offsetTop - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height = (void 0) - if (cur.hidden) { continue } - if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight - height = bot - prevBottom - prevBottom = bot - } else { - var box = cur.node.getBoundingClientRect() - height = box.bottom - box.top - } - var diff = cur.line.height - height - if (height < 2) { height = textHeight(display) } - if (diff > .005 || diff < -.005) { - updateLineHeight(cur.line, height) - updateWidgetHeight(cur.line) - if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) - { updateWidgetHeight(cur.rest[j]) } } - } - } - } - - // Read and store the height of line widgets associated with the - // given line. - function updateWidgetHeight(line) { - if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) { - var w = line.widgets[i], parent = w.node.parentNode - if (parent) { w.height = parent.offsetHeight } - } } - } - - // Compute the lines that are visible in a given viewport (defaults - // the the current scroll position). viewport may contain top, - // height, and ensure (see op.scrollToPos) properties. - function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop - top = Math.floor(top - paddingTop(display)) - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight - - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) - // Ensure is a {from: {line, ch}, to: {line, ch}} object, and - // forces those lines into the viewport (if possible). - if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line - if (ensureFrom < from) { - from = ensureFrom - to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight) - } else if (Math.min(ensureTo, doc.lastLine()) >= to) { - from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight) - to = ensureTo - } - } - return {from: from, to: Math.max(to, from + 1)} - } - - // Re-align line numbers and gutter marks to compensate for - // horizontal scrolling. - function alignHorizontally(cm) { - var display = cm.display, view = display.view - if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return } - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft - var gutterW = display.gutters.offsetWidth, left = comp + "px" - for (var i = 0; i < view.length; i++) { if (!view[i].hidden) { - if (cm.options.fixedGutter) { - if (view[i].gutter) - { view[i].gutter.style.left = left } - if (view[i].gutterBackground) - { view[i].gutterBackground.style.left = left } - } - var align = view[i].alignable - if (align) { for (var j = 0; j < align.length; j++) - { align[j].style.left = left } } - } } - if (cm.options.fixedGutter) - { display.gutters.style.left = (comp + gutterW) + "px" } - } - - // Used to ensure that the line number gutter is still the right - // size for the current document size. Returns true when an update - // is needed. - function maybeUpdateLineNumberWidth(cm) { - if (!cm.options.lineNumbers) { return false } - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display - if (last.length != display.lineNumChars) { - var test = display.measure.appendChild(elt("div", [elt("div", last)], - "CodeMirror-linenumber CodeMirror-gutter-elt")) - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW - display.lineGutter.style.width = "" - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1 - display.lineNumWidth = display.lineNumInnerWidth + padding - display.lineNumChars = display.lineNumInnerWidth ? last.length : -1 - display.lineGutter.style.width = display.lineNumWidth + "px" - updateGutterSpace(cm) - return true - } - return false - } - - // SCROLLING THINGS INTO VIEW - - // If an editor sits on the top or bottom of the window, partially - // scrolled out of view, this ensures that the cursor is visible. - function maybeScrollWindow(cm, rect) { - if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } - - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null - if (rect.top + box.top < 0) { doScroll = true } - else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false } - if (doScroll != null && !phantom) { - var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")) - cm.display.lineSpace.appendChild(scrollNode) - scrollNode.scrollIntoView(doScroll) - cm.display.lineSpace.removeChild(scrollNode) - } - } - - // Scroll a given position into view (immediately), verifying that - // it actually became visible (as line heights are accurately - // measured, the position of something may 'drift' during drawing). - function scrollPosIntoView(cm, pos, end, margin) { - if (margin == null) { margin = 0 } - var rect - if (!cm.options.lineWrapping && pos == end) { - // Set pos and end to the cursor positions around the character pos sticks to - // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch - // If pos == Pos(_, 0, "before"), pos and end are unchanged - pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos - end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos - } - for (var limit = 0; limit < 5; limit++) { - var changed = false - var coords = cursorCoords(cm, pos) - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end) - rect = {left: Math.min(coords.left, endCoords.left), - top: Math.min(coords.top, endCoords.top) - margin, - right: Math.max(coords.left, endCoords.left), - bottom: Math.max(coords.bottom, endCoords.bottom) + margin} - var scrollPos = calculateScrollPos(cm, rect) - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft - if (scrollPos.scrollTop != null) { - updateScrollTop(cm, scrollPos.scrollTop) - if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true } - } - if (scrollPos.scrollLeft != null) { - setScrollLeft(cm, scrollPos.scrollLeft) - if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true } - } - if (!changed) { break } - } - return rect - } - - // Scroll a given set of coordinates into view (immediately). - function scrollIntoView(cm, rect) { - var scrollPos = calculateScrollPos(cm, rect) - if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop) } - if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft) } - } - - // Calculate a new scroll position needed to scroll the given - // rectangle into view. Returns an object with scrollTop and - // scrollLeft properties. When these are undefined, the - // vertical/horizontal position does not need to be adjusted. - function calculateScrollPos(cm, rect) { - var display = cm.display, snapMargin = textHeight(cm.display) - if (rect.top < 0) { rect.top = 0 } - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop - var screen = displayHeight(cm), result = {} - if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen } - var docBottom = cm.doc.height + paddingVert(display) - var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin - if (rect.top < screentop) { - result.scrollTop = atTop ? 0 : rect.top - } else if (rect.bottom > screentop + screen) { - var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen) - if (newTop != screentop) { result.scrollTop = newTop } - } - - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) - var tooWide = rect.right - rect.left > screenw - if (tooWide) { rect.right = rect.left + screenw } - if (rect.left < 10) - { result.scrollLeft = 0 } - else if (rect.left < screenleft) - { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)) } - else if (rect.right > screenw + screenleft - 3) - { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw } - return result - } - - // Store a relative adjustment to the scroll position in the current - // operation (to be applied when the operation finishes). - function addToScrollTop(cm, top) { - if (top == null) { return } - resolveScrollToPos(cm) - cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top - } - - // Make sure that at the end of the operation the current cursor is - // shown. - function ensureCursorVisible(cm) { - resolveScrollToPos(cm) - var cur = cm.getCursor() - cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin} - } - - function scrollToCoords(cm, x, y) { - if (x != null || y != null) { resolveScrollToPos(cm) } - if (x != null) { cm.curOp.scrollLeft = x } - if (y != null) { cm.curOp.scrollTop = y } - } - - function scrollToRange(cm, range) { - resolveScrollToPos(cm) - cm.curOp.scrollToPos = range - } - - // When an operation has its scrollToPos property set, and another - // scroll action is applied before the end of the operation, this - // 'simulates' scrolling that position into view in a cheap way, so - // that the effect of intermediate scroll commands is not ignored. - function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos - if (range) { - cm.curOp.scrollToPos = null - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) - scrollToCoordsRange(cm, from, to, range.margin) - } - } - - function scrollToCoordsRange(cm, from, to, margin) { - var sPos = calculateScrollPos(cm, { - left: Math.min(from.left, to.left), - top: Math.min(from.top, to.top) - margin, - right: Math.max(from.right, to.right), - bottom: Math.max(from.bottom, to.bottom) + margin - }) - scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop) - } - - // Sync the scrollable area and scrollbars, ensure the viewport - // covers the visible area. - function updateScrollTop(cm, val) { - if (Math.abs(cm.doc.scrollTop - val) < 2) { return } - if (!gecko) { updateDisplaySimple(cm, {top: val}) } - setScrollTop(cm, val, true) - if (gecko) { updateDisplaySimple(cm) } - startWorker(cm, 100) - } - - function setScrollTop(cm, val, forceScroll) { - val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val) - if (cm.display.scroller.scrollTop == val && !forceScroll) { return } - cm.doc.scrollTop = val - cm.display.scrollbars.setScrollTop(val) - if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val } - } - - // Sync scroller and scrollbar, ensure the gutter elements are - // aligned. - function setScrollLeft(cm, val, isScroller, forceScroll) { - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth) - if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } - cm.doc.scrollLeft = val - alignHorizontally(cm) - if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val } - cm.display.scrollbars.setScrollLeft(val) - } - - // SCROLLBARS - - // Prepare DOM reads needed to update the scrollbars. Done in one - // shot to minimize update/measure roundtrips. - function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth - var docH = Math.round(cm.doc.height + paddingVert(cm.display)) - return { - clientHeight: d.scroller.clientHeight, - viewHeight: d.wrapper.clientHeight, - scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, - viewWidth: d.wrapper.clientWidth, - barLeft: cm.options.fixedGutter ? gutterW : 0, - docHeight: docH, - scrollHeight: docH + scrollGap(cm) + d.barHeight, - nativeBarWidth: d.nativeBarWidth, - gutterWidth: gutterW - } - } - - var NativeScrollbars = function(place, scroll, cm) { - this.cm = cm - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") - place(vert); place(horiz) - - on(vert, "scroll", function () { - if (vert.clientHeight) { scroll(vert.scrollTop, "vertical") } - }) - on(horiz, "scroll", function () { - if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal") } - }) - - this.checkedZeroWidth = false - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" } - }; - - NativeScrollbars.prototype.update = function (measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1 - var needsV = measure.scrollHeight > measure.clientHeight + 1 - var sWidth = measure.nativeBarWidth - - if (needsV) { - this.vert.style.display = "block" - this.vert.style.bottom = needsH ? sWidth + "px" : "0" - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0) - // A bug in IE8 can cause this value to be negative, so guard it. - this.vert.firstChild.style.height = - Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px" - } else { - this.vert.style.display = "" - this.vert.firstChild.style.height = "0" - } - - if (needsH) { - this.horiz.style.display = "block" - this.horiz.style.right = needsV ? sWidth + "px" : "0" - this.horiz.style.left = measure.barLeft + "px" - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) - this.horiz.firstChild.style.width = - Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px" - } else { - this.horiz.style.display = "" - this.horiz.firstChild.style.width = "0" - } - - if (!this.checkedZeroWidth && measure.clientHeight > 0) { - if (sWidth == 0) { this.zeroWidthHack() } - this.checkedZeroWidth = true - } - - return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} - }; - - NativeScrollbars.prototype.setScrollLeft = function (pos) { - if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos } - if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz") } - }; - - NativeScrollbars.prototype.setScrollTop = function (pos) { - if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos } - if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert") } - }; - - NativeScrollbars.prototype.zeroWidthHack = function () { - var w = mac && !mac_geMountainLion ? "12px" : "18px" - this.horiz.style.height = this.vert.style.width = w - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" - this.disableHoriz = new Delayed - this.disableVert = new Delayed - }; - - NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) { - bar.style.pointerEvents = "auto" - function maybeDisable() { - // To find out whether the scrollbar is still visible, we - // check whether the element under the pixel in the bottom - // right corner of the scrollbar box is the scrollbar box - // itself (when the bar is still visible) or its filler child - // (when the bar is hidden). If it is still visible, we keep - // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect() - var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) - : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1) - if (elt != bar) { bar.style.pointerEvents = "none" } - else { delay.set(1000, maybeDisable) } - } - delay.set(1000, maybeDisable) - }; - - NativeScrollbars.prototype.clear = function () { - var parent = this.horiz.parentNode - parent.removeChild(this.horiz) - parent.removeChild(this.vert) - }; - - var NullScrollbars = function () {}; - - NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} }; - NullScrollbars.prototype.setScrollLeft = function () {}; - NullScrollbars.prototype.setScrollTop = function () {}; - NullScrollbars.prototype.clear = function () {}; - - function updateScrollbars(cm, measure) { - if (!measure) { measure = measureForScrollbars(cm) } - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight - updateScrollbarsInner(cm, measure) - for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { - if (startWidth != cm.display.barWidth && cm.options.lineWrapping) - { updateHeightsInViewport(cm) } - updateScrollbarsInner(cm, measureForScrollbars(cm)) - startWidth = cm.display.barWidth; startHeight = cm.display.barHeight - } - } - - // Re-synchronize the fake scrollbars with the actual size of the - // content. - function updateScrollbarsInner(cm, measure) { - var d = cm.display - var sizes = d.scrollbars.update(measure) - - d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px" - d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px" - d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" - - if (sizes.right && sizes.bottom) { - d.scrollbarFiller.style.display = "block" - d.scrollbarFiller.style.height = sizes.bottom + "px" - d.scrollbarFiller.style.width = sizes.right + "px" - } else { d.scrollbarFiller.style.display = "" } - if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { - d.gutterFiller.style.display = "block" - d.gutterFiller.style.height = sizes.bottom + "px" - d.gutterFiller.style.width = measure.gutterWidth + "px" - } else { d.gutterFiller.style.display = "" } - } - - var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} - - function initScrollbars(cm) { - if (cm.display.scrollbars) { - cm.display.scrollbars.clear() - if (cm.display.scrollbars.addClass) - { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) } - } - - cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) { - cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller) - // Prevent clicks in the scrollbars from killing focus - on(node, "mousedown", function () { - if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0) } - }) - node.setAttribute("cm-not-content", "true") - }, function (pos, axis) { - if (axis == "horizontal") { setScrollLeft(cm, pos) } - else { updateScrollTop(cm, pos) } - }, cm) - if (cm.display.scrollbars.addClass) - { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) } - } - - // Operations are used to wrap a series of changes to the editor - // state in such a way that each change won't have to update the - // cursor and display (which would be awkward, slow, and - // error-prone). Instead, display updates are batched and then all - // combined and executed at once. - - var nextOpId = 0 - // Start a new operation. - function startOperation(cm) { - cm.curOp = { - cm: cm, - viewChanged: false, // Flag that indicates that lines might need to be redrawn - startHeight: cm.doc.height, // Used to detect need to update scrollbar - forceUpdate: false, // Used to force a redraw - updateInput: null, // Whether to reset the input textarea - typing: false, // Whether this reset should be careful to leave existing text (for compositing) - changeObjs: null, // Accumulated changes, for firing change events - cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on - cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already - selectionChanged: false, // Whether the selection needs to be redrawn - updateMaxLine: false, // Set when the widest line needs to be determined anew - scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet - scrollToPos: null, // Used to scroll to a specific position - focus: false, - id: ++nextOpId // Unique ID - } - pushOperation(cm.curOp) - } - - // Finish an operation, updating the display and signalling delayed events - function endOperation(cm) { - var op = cm.curOp - finishOperation(op, function (group) { - for (var i = 0; i < group.ops.length; i++) - { group.ops[i].cm.curOp = null } - endOperations(group) - }) - } - - // The DOM updates done when an operation finishes are batched so - // that the minimum number of relayouts are required. - function endOperations(group) { - var ops = group.ops - for (var i = 0; i < ops.length; i++) // Read DOM - { endOperation_R1(ops[i]) } - for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe) - { endOperation_W1(ops[i$1]) } - for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM - { endOperation_R2(ops[i$2]) } - for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe) - { endOperation_W2(ops[i$3]) } - for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM - { endOperation_finish(ops[i$4]) } - } - - function endOperation_R1(op) { - var cm = op.cm, display = cm.display - maybeClipScrollbars(cm) - if (op.updateMaxLine) { findMaxLine(cm) } - - op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || - op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || - op.scrollToPos.to.line >= display.viewTo) || - display.maxLineChanged && cm.options.lineWrapping - op.update = op.mustUpdate && - new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate) - } - - function endOperation_W1(op) { - op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update) - } - - function endOperation_R2(op) { - var cm = op.cm, display = cm.display - if (op.updatedDisplay) { updateHeightsInViewport(cm) } - - op.barMeasure = measureForScrollbars(cm) - - // If the max line changed since it was last measured, measure it, - // and ensure the document's width matches it. - // updateDisplay_W2 will use these properties to do the actual resizing - if (display.maxLineChanged && !cm.options.lineWrapping) { - op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3 - cm.display.sizerWidth = op.adjustWidthTo - op.barMeasure.scrollWidth = - Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth) - op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)) - } - - if (op.updatedDisplay || op.selectionChanged) - { op.preparedSelection = display.input.prepareSelection() } - } - - function endOperation_W2(op) { - var cm = op.cm - - if (op.adjustWidthTo != null) { - cm.display.sizer.style.minWidth = op.adjustWidthTo + "px" - if (op.maxScrollLeft < cm.doc.scrollLeft) - { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) } - cm.display.maxLineChanged = false - } - - var takeFocus = op.focus && op.focus == activeElt() - if (op.preparedSelection) - { cm.display.input.showSelection(op.preparedSelection, takeFocus) } - if (op.updatedDisplay || op.startHeight != cm.doc.height) - { updateScrollbars(cm, op.barMeasure) } - if (op.updatedDisplay) - { setDocumentHeight(cm, op.barMeasure) } - - if (op.selectionChanged) { restartBlink(cm) } - - if (cm.state.focused && op.updateInput) - { cm.display.input.reset(op.typing) } - if (takeFocus) { ensureFocus(op.cm) } - } - - function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc - - if (op.updatedDisplay) { postUpdateDisplay(cm, op.update) } - - // Abort mouse wheel delta measurement, when scrolling explicitly - if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) - { display.wheelStartX = display.wheelStartY = null } - - // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll) } - - if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true) } - // If we need to scroll a specific position into view, do so. - if (op.scrollToPos) { - var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), - clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin) - maybeScrollWindow(cm, rect) - } - - // Fire events for markers that are hidden/unidden by editing or - // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers - if (hidden) { for (var i = 0; i < hidden.length; ++i) - { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } } - if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1) - { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide") } } } - - if (display.wrapper.offsetHeight) - { doc.scrollTop = cm.display.scroller.scrollTop } - - // Fire change events, and delayed event handlers - if (op.changeObjs) - { signal(cm, "changes", cm, op.changeObjs) } - if (op.update) - { op.update.finish() } - } - - // Run the given function in an operation - function runInOp(cm, f) { - if (cm.curOp) { return f() } - startOperation(cm) - try { return f() } - finally { endOperation(cm) } - } - // Wraps a function in an operation. Returns the wrapped function. - function operation(cm, f) { - return function() { - if (cm.curOp) { return f.apply(cm, arguments) } - startOperation(cm) - try { return f.apply(cm, arguments) } - finally { endOperation(cm) } - } - } - // Used to add methods to editor and doc instances, wrapping them in - // operations. - function methodOp(f) { - return function() { - if (this.curOp) { return f.apply(this, arguments) } - startOperation(this) - try { return f.apply(this, arguments) } - finally { endOperation(this) } - } - } - function docMethodOp(f) { - return function() { - var cm = this.cm - if (!cm || cm.curOp) { return f.apply(this, arguments) } - startOperation(cm) - try { return f.apply(this, arguments) } - finally { endOperation(cm) } - } - } - - // Updates the display.view data structure for a given change to the - // document. From and to are in pre-change coordinates. Lendiff is - // the amount of lines added or subtracted by the change. This is - // used for changes that span multiple lines, or change the way - // lines are divided into visual lines. regLineChange (below) - // registers single-line changes. - function regChange(cm, from, to, lendiff) { - if (from == null) { from = cm.doc.first } - if (to == null) { to = cm.doc.first + cm.doc.size } - if (!lendiff) { lendiff = 0 } - - var display = cm.display - if (lendiff && to < display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers > from)) - { display.updateLineNumbers = from } - - cm.curOp.viewChanged = true - - if (from >= display.viewTo) { // Change after - if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) - { resetView(cm) } - } else if (to <= display.viewFrom) { // Change before - if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { - resetView(cm) - } else { - display.viewFrom += lendiff - display.viewTo += lendiff - } - } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap - resetView(cm) - } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1) - if (cut) { - display.view = display.view.slice(cut.index) - display.viewFrom = cut.lineN - display.viewTo += lendiff - } else { - resetView(cm) - } - } else if (to >= display.viewTo) { // Bottom overlap - var cut$1 = viewCuttingPoint(cm, from, from, -1) - if (cut$1) { - display.view = display.view.slice(0, cut$1.index) - display.viewTo = cut$1.lineN - } else { - resetView(cm) - } - } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1) - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) - if (cutTop && cutBot) { - display.view = display.view.slice(0, cutTop.index) - .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) - .concat(display.view.slice(cutBot.index)) - display.viewTo += lendiff - } else { - resetView(cm) - } - } - - var ext = display.externalMeasured - if (ext) { - if (to < ext.lineN) - { ext.lineN += lendiff } - else if (from < ext.lineN + ext.size) - { display.externalMeasured = null } - } - } - - // Register a change to a single line. Type must be one of "text", - // "gutter", "class", "widget" - function regLineChange(cm, line, type) { - cm.curOp.viewChanged = true - var display = cm.display, ext = cm.display.externalMeasured - if (ext && line >= ext.lineN && line < ext.lineN + ext.size) - { display.externalMeasured = null } - - if (line < display.viewFrom || line >= display.viewTo) { return } - var lineView = display.view[findViewIndex(cm, line)] - if (lineView.node == null) { return } - var arr = lineView.changes || (lineView.changes = []) - if (indexOf(arr, type) == -1) { arr.push(type) } - } - - // Clear the view. - function resetView(cm) { - cm.display.viewFrom = cm.display.viewTo = cm.doc.first - cm.display.view = [] - cm.display.viewOffset = 0 - } - - function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view - if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) - { return {index: index, lineN: newN} } - var n = cm.display.viewFrom - for (var i = 0; i < index; i++) - { n += view[i].size } - if (n != oldN) { - if (dir > 0) { - if (index == view.length - 1) { return null } - diff = (n + view[index].size) - oldN - index++ - } else { - diff = n - oldN - } - oldN += diff; newN += diff - } - while (visualLineNo(cm.doc, newN) != newN) { - if (index == (dir < 0 ? 0 : view.length - 1)) { return null } - newN += dir * view[index - (dir < 0 ? 1 : 0)].size - index += dir - } - return {index: index, lineN: newN} - } - - // Force the view to cover a given range, adding empty view element - // or clipping off existing ones as needed. - function adjustView(cm, from, to) { - var display = cm.display, view = display.view - if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { - display.view = buildViewArray(cm, from, to) - display.viewFrom = from - } else { - if (display.viewFrom > from) - { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) } - else if (display.viewFrom < from) - { display.view = display.view.slice(findViewIndex(cm, from)) } - display.viewFrom = from - if (display.viewTo < to) - { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) } - else if (display.viewTo > to) - { display.view = display.view.slice(0, findViewIndex(cm, to)) } - } - display.viewTo = to - } - - // Count the number of lines in the view whose DOM representation is - // out of date (or nonexistent). - function countDirtyView(cm) { - var view = cm.display.view, dirty = 0 - for (var i = 0; i < view.length; i++) { - var lineView = view[i] - if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty } - } - return dirty - } - - // HIGHLIGHT WORKER - - function startWorker(cm, time) { - if (cm.doc.highlightFrontier < cm.display.viewTo) - { cm.state.highlight.set(time, bind(highlightWorker, cm)) } - } - - function highlightWorker(cm) { - var doc = cm.doc - if (doc.highlightFrontier >= cm.display.viewTo) { return } - var end = +new Date + cm.options.workTime - var context = getContextBefore(cm, doc.highlightFrontier) - var changedLines = [] - - doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { - if (context.line >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles - var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null - var highlighted = highlightLine(cm, line, context, true) - if (resetState) { context.state = resetState } - line.styles = highlighted.styles - var oldCls = line.styleClasses, newCls = highlighted.classes - if (newCls) { line.styleClasses = newCls } - else if (oldCls) { line.styleClasses = null } - var ischange = !oldStyles || oldStyles.length != line.styles.length || - oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass) - for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] } - if (ischange) { changedLines.push(context.line) } - line.stateAfter = context.save() - context.nextLine() - } else { - if (line.text.length <= cm.options.maxHighlightLength) - { processLine(cm, line.text, context) } - line.stateAfter = context.line % 5 == 0 ? context.save() : null - context.nextLine() - } - if (+new Date > end) { - startWorker(cm, cm.options.workDelay) - return true - } - }) - doc.highlightFrontier = context.line - doc.modeFrontier = Math.max(doc.modeFrontier, context.line) - if (changedLines.length) { runInOp(cm, function () { - for (var i = 0; i < changedLines.length; i++) - { regLineChange(cm, changedLines[i], "text") } - }) } - } - - // DISPLAY DRAWING - - var DisplayUpdate = function(cm, viewport, force) { - var display = cm.display - - this.viewport = viewport - // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport) - this.editorIsHidden = !display.wrapper.offsetWidth - this.wrapperHeight = display.wrapper.clientHeight - this.wrapperWidth = display.wrapper.clientWidth - this.oldDisplayWidth = displayWidth(cm) - this.force = force - this.dims = getDimensions(cm) - this.events = [] - }; - - DisplayUpdate.prototype.signal = function (emitter, type) { - if (hasHandler(emitter, type)) - { this.events.push(arguments) } - }; - DisplayUpdate.prototype.finish = function () { - var this$1 = this; - - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this$1.events[i]) } - }; - - function maybeClipScrollbars(cm) { - var display = cm.display - if (!display.scrollbarsClipped && display.scroller.offsetWidth) { - display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth - display.heightForcer.style.height = scrollGap(cm) + "px" - display.sizer.style.marginBottom = -display.nativeBarWidth + "px" - display.sizer.style.borderRightWidth = scrollGap(cm) + "px" - display.scrollbarsClipped = true - } - } - - function selectionSnapshot(cm) { - if (cm.hasFocus()) { return null } - var active = activeElt() - if (!active || !contains(cm.display.lineDiv, active)) { return null } - var result = {activeElt: active} - if (window.getSelection) { - var sel = window.getSelection() - if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) { - result.anchorNode = sel.anchorNode - result.anchorOffset = sel.anchorOffset - result.focusNode = sel.focusNode - result.focusOffset = sel.focusOffset - } - } - return result - } - - function restoreSelection(snapshot) { - if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } - snapshot.activeElt.focus() - if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { - var sel = window.getSelection(), range = document.createRange() - range.setEnd(snapshot.anchorNode, snapshot.anchorOffset) - range.collapse(false) - sel.removeAllRanges() - sel.addRange(range) - sel.extend(snapshot.focusNode, snapshot.focusOffset) - } - } - - // Does the actual updating of the line display. Bails out - // (returning false) when there is nothing to be done and forced is - // false. - function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc - - if (update.editorIsHidden) { - resetView(cm) - return false - } - - // Bail out if the visible area is already rendered and nothing changed. - if (!update.force && - update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && - display.renderedView == display.view && countDirtyView(cm) == 0) - { return false } - - if (maybeUpdateLineNumberWidth(cm)) { - resetView(cm) - update.dims = getDimensions(cm) - } - - // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) - var to = Math.min(end, update.visible.to + cm.options.viewportMargin) - if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom) } - if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo) } - if (sawCollapsedSpans) { - from = visualLineNo(cm.doc, from) - to = visualLineEndNo(cm.doc, to) - } - - var different = from != display.viewFrom || to != display.viewTo || - display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth - adjustView(cm, from, to) - - display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)) - // Position the mover div to align with the current scroll position - cm.display.mover.style.top = display.viewOffset + "px" - - var toUpdate = countDirtyView(cm) - if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) - { return false } - - // For big changes, we hide the enclosing element during the - // update, since that speeds up the operations on most browsers. - var selSnapshot = selectionSnapshot(cm) - if (toUpdate > 4) { display.lineDiv.style.display = "none" } - patchDisplay(cm, display.updateLineNumbers, update.dims) - if (toUpdate > 4) { display.lineDiv.style.display = "" } - display.renderedView = display.view - // There might have been a widget with a focused element that got - // hidden or updated, if so re-focus it. - restoreSelection(selSnapshot) - - // Prevent selection and cursors from interfering with the scroll - // width and height. - removeChildren(display.cursorDiv) - removeChildren(display.selectionDiv) - display.gutters.style.height = display.sizer.style.minHeight = 0 - - if (different) { - display.lastWrapHeight = update.wrapperHeight - display.lastWrapWidth = update.wrapperWidth - startWorker(cm, 400) - } - - display.updateLineNumbers = null - - return true - } - - function postUpdateDisplay(cm, update) { - var viewport = update.viewport - - for (var first = true;; first = false) { - if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { - // Clip forced viewport to actual scrollable area. - if (viewport && viewport.top != null) - { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)} } - // Updated line heights might result in the drawn area not - // actually covering the viewport. Keep looping until it does. - update.visible = visibleLines(cm.display, cm.doc, viewport) - if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) - { break } - } - if (!updateDisplayIfNeeded(cm, update)) { break } - updateHeightsInViewport(cm) - var barMeasure = measureForScrollbars(cm) - updateSelection(cm) - updateScrollbars(cm, barMeasure) - setDocumentHeight(cm, barMeasure) - update.force = false - } - - update.signal(cm, "update", cm) - if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo) - cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo - } - } - - function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport) - if (updateDisplayIfNeeded(cm, update)) { - updateHeightsInViewport(cm) - postUpdateDisplay(cm, update) - var barMeasure = measureForScrollbars(cm) - updateSelection(cm) - updateScrollbars(cm, barMeasure) - setDocumentHeight(cm, barMeasure) - update.finish() - } - } - - // Sync the actual display DOM structure with display.view, removing - // nodes for lines that are no longer in view, and creating the ones - // that are not there yet, and updating the ones that are out of - // date. - function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers - var container = display.lineDiv, cur = container.firstChild - - function rm(node) { - var next = node.nextSibling - // Works around a throw-scroll bug in OS X Webkit - if (webkit && mac && cm.display.currentWheelTarget == node) - { node.style.display = "none" } - else - { node.parentNode.removeChild(node) } - return next - } - - var view = display.view, lineN = display.viewFrom - // Loop over the elements in the view, syncing cur (the DOM nodes - // in display.lineDiv) with the view as we go. - for (var i = 0; i < view.length; i++) { - var lineView = view[i] - if (lineView.hidden) { - } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims) - container.insertBefore(node, cur) - } else { // Already drawn - while (cur != lineView.node) { cur = rm(cur) } - var updateNumber = lineNumbers && updateNumbersFrom != null && - updateNumbersFrom <= lineN && lineView.lineNumber - if (lineView.changes) { - if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false } - updateLineForChanges(cm, lineView, lineN, dims) - } - if (updateNumber) { - removeChildren(lineView.lineNumber) - lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))) - } - cur = lineView.node.nextSibling - } - lineN += lineView.size - } - while (cur) { cur = rm(cur) } - } - - function updateGutterSpace(cm) { - var width = cm.display.gutters.offsetWidth - cm.display.sizer.style.marginLeft = width + "px" - } - - function setDocumentHeight(cm, measure) { - cm.display.sizer.style.minHeight = measure.docHeight + "px" - cm.display.heightForcer.style.top = measure.docHeight + "px" - cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px" - } - - // Rebuild the gutter elements, ensure the margin to the left of the - // code matches their width. - function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters - removeChildren(gutters) - var i = 0 - for (; i < specs.length; ++i) { - var gutterClass = specs[i] - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) - if (gutterClass == "CodeMirror-linenumbers") { - cm.display.lineGutter = gElt - gElt.style.width = (cm.display.lineNumWidth || 1) + "px" - } - } - gutters.style.display = i ? "" : "none" - updateGutterSpace(cm) - } - - // Make sure the gutters options contains the element - // "CodeMirror-linenumbers" when the lineNumbers option is true. - function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers") - if (found == -1 && options.lineNumbers) { - options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) - } else if (found > -1 && !options.lineNumbers) { - options.gutters = options.gutters.slice(0) - options.gutters.splice(found, 1) - } - } - - var wheelSamples = 0; - var wheelPixelsPerUnit = null; - // Fill in a browser-detected starting value on browsers where we - // know one. These don't have to be accurate -- the result of them - // being wrong would just be a slight flicker on the first wheel - // scroll (if it is large enough). - if (ie) { wheelPixelsPerUnit = -.53 } - else if (gecko) { wheelPixelsPerUnit = 15 } - else if (chrome) { wheelPixelsPerUnit = -.7 } - else if (safari) { wheelPixelsPerUnit = -1/3 } - - function wheelEventDelta(e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail } - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail } - else if (dy == null) { dy = e.wheelDelta } - return {x: dx, y: dy} - } - function wheelEventPixels(e) { - var delta = wheelEventDelta(e) - delta.x *= wheelPixelsPerUnit - delta.y *= wheelPixelsPerUnit - return delta - } - - function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y - - var display = cm.display, scroll = display.scroller - // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth - var canScrollY = scroll.scrollHeight > scroll.clientHeight - if (!(dx && canScrollX || dy && canScrollY)) { return } - - // Webkit browsers on OS X abort momentum scrolls when the target - // of the scroll event is removed from the scrollable element. - // This hack (see related code in patchDisplay) makes sure the - // element is kept around. - if (dy && mac && webkit) { - outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { - for (var i = 0; i < view.length; i++) { - if (view[i].node == cur) { - cm.display.currentWheelTarget = cur - break outer - } - } - } - } - - // On some browsers, horizontal scrolling will cause redraws to - // happen before the gutter has been realigned, causing it to - // wriggle around in a most unseemly way. When we have an - // estimated pixels/delta value, we just handle horizontal - // scrolling entirely here. It'll be slightly off from native, but - // better than glitching out. - if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { - if (dy && canScrollY) - { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)) } - setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit)) - // Only prevent default scrolling if vertical scrolling is - // actually possible. Otherwise, it causes vertical scroll - // jitter on OSX trackpads when deltaX is small and deltaY - // is large (issue #3579) - if (!dy || (dy && canScrollY)) - { e_preventDefault(e) } - display.wheelStartX = null // Abort measurement, if in progress - return - } - - // 'Project' the visible viewport to cover the area that is being - // scrolled into view (if we know enough to estimate it). - if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight - if (pixels < 0) { top = Math.max(0, top + pixels - 50) } - else { bot = Math.min(cm.doc.height, bot + pixels + 50) } - updateDisplaySimple(cm, {top: top, bottom: bot}) - } - - if (wheelSamples < 20) { - if (display.wheelStartX == null) { - display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop - display.wheelDX = dx; display.wheelDY = dy - setTimeout(function () { - if (display.wheelStartX == null) { return } - var movedX = scroll.scrollLeft - display.wheelStartX - var movedY = scroll.scrollTop - display.wheelStartY - var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || - (movedX && display.wheelDX && movedX / display.wheelDX) - display.wheelStartX = display.wheelStartY = null - if (!sample) { return } - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1) - ++wheelSamples - }, 200) - } else { - display.wheelDX += dx; display.wheelDY += dy - } - } - } - - // Selection objects are immutable. A new one is created every time - // the selection changes. A selection is one or more non-overlapping - // (and non-touching) ranges, sorted, and an integer that indicates - // which one is the primary selection (the one that's scrolled into - // view, that getCursor returns, etc). - var Selection = function(ranges, primIndex) { - this.ranges = ranges - this.primIndex = primIndex - }; - - Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; - - Selection.prototype.equals = function (other) { - var this$1 = this; - - if (other == this) { return true } - if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } - for (var i = 0; i < this.ranges.length; i++) { - var here = this$1.ranges[i], there = other.ranges[i] - if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } - } - return true - }; - - Selection.prototype.deepCopy = function () { - var this$1 = this; - - var out = [] - for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) } - return new Selection(out, this.primIndex) - }; - - Selection.prototype.somethingSelected = function () { - var this$1 = this; - - for (var i = 0; i < this.ranges.length; i++) - { if (!this$1.ranges[i].empty()) { return true } } - return false - }; - - Selection.prototype.contains = function (pos, end) { - var this$1 = this; - - if (!end) { end = pos } - for (var i = 0; i < this.ranges.length; i++) { - var range = this$1.ranges[i] - if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) - { return i } - } - return -1 - }; - - var Range = function(anchor, head) { - this.anchor = anchor; this.head = head - }; - - Range.prototype.from = function () { return minPos(this.anchor, this.head) }; - Range.prototype.to = function () { return maxPos(this.anchor, this.head) }; - Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }; - - // Take an unsorted, potentially overlapping set of ranges, and - // build a selection out of it. 'Consumes' ranges array (modifying - // it). - function normalizeSelection(ranges, primIndex) { - var prim = ranges[primIndex] - ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }) - primIndex = indexOf(ranges, prim) - for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1] - if (cmp(prev.to(), cur.from()) >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head - if (i <= primIndex) { --primIndex } - ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) - } - } - return new Selection(ranges, primIndex) - } - - function simpleSelection(anchor, head) { - return new Selection([new Range(anchor, head || anchor)], 0) - } - - // Compute the position of the end of a change (its 'to' property - // refers to the pre-change end). - function changeEnd(change) { - if (!change.text) { return change.to } - return Pos(change.from.line + change.text.length - 1, - lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) - } - - // Adjust a position to refer to the post-change position of the - // same text, or the end of the change if the change covers it. - function adjustForChange(pos, change) { - if (cmp(pos, change.from) < 0) { return pos } - if (cmp(pos, change.to) <= 0) { return changeEnd(change) } - - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch - if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch } - return Pos(line, ch) - } - - function computeSelAfterChange(doc, change) { - var out = [] - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i] - out.push(new Range(adjustForChange(range.anchor, change), - adjustForChange(range.head, change))) - } - return normalizeSelection(out, doc.sel.primIndex) - } - - function offsetPos(pos, old, nw) { - if (pos.line == old.line) - { return Pos(nw.line, pos.ch - old.ch + nw.ch) } - else - { return Pos(nw.line + (pos.line - old.line), pos.ch) } - } - - // Used by replaceSelections to allow moving the selection to the - // start or around the replaced test. Hint may be "start" or "around". - function computeReplacedSel(doc, changes, hint) { - var out = [] - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev - for (var i = 0; i < changes.length; i++) { - var change = changes[i] - var from = offsetPos(change.from, oldPrev, newPrev) - var to = offsetPos(changeEnd(change), oldPrev, newPrev) - oldPrev = change.to - newPrev = to - if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 - out[i] = new Range(inv ? to : from, inv ? from : to) - } else { - out[i] = new Range(from, from) - } - } - return new Selection(out, doc.sel.primIndex) - } - - // Used to get the editor into a consistent state again when options change. - - function loadMode(cm) { - cm.doc.mode = getMode(cm.options, cm.doc.modeOption) - resetModeState(cm) - } - - function resetModeState(cm) { - cm.doc.iter(function (line) { - if (line.stateAfter) { line.stateAfter = null } - if (line.styles) { line.styles = null } - }) - cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first - startWorker(cm, 100) - cm.state.modeGen++ - if (cm.curOp) { regChange(cm) } - } - - // DOCUMENT DATA STRUCTURE - - // By default, updates that start and end at the beginning of a line - // are treated specially, in order to make the association of line - // widgets and marker elements with the text behave more intuitive. - function isWholeLineUpdate(doc, change) { - return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && - (!doc.cm || doc.cm.options.wholeLineUpdateBefore) - } - - // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight) { - function spansFor(n) {return markedSpans ? markedSpans[n] : null} - function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight) - signalLater(line, "change", line, change) - } - function linesFor(start, end) { - var result = [] - for (var i = start; i < end; ++i) - { result.push(new Line(text[i], spansFor(i), estimateHeight)) } - return result - } - - var from = change.from, to = change.to, text = change.text - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line - - // Adjust the line structure - if (change.full) { - doc.insert(0, linesFor(0, text.length)) - doc.remove(text.length, doc.size - text.length) - } else if (isWholeLineUpdate(doc, change)) { - // This is a whole-line replace. Treated specially to make - // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1) - update(lastLine, lastLine.text, lastSpans) - if (nlines) { doc.remove(from.line, nlines) } - if (added.length) { doc.insert(from.line, added) } - } else if (firstLine == lastLine) { - if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans) - } else { - var added$1 = linesFor(1, text.length - 1) - added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)) - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) - doc.insert(from.line + 1, added$1) - } - } else if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)) - doc.remove(from.line + 1, nlines) - } else { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) - update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans) - var added$2 = linesFor(1, text.length - 1) - if (nlines > 1) { doc.remove(from.line + 1, nlines - 1) } - doc.insert(from.line + 1, added$2) - } - - signalLater(doc, "change", doc, change) - } - - // Call f for all linked documents. - function linkedDocs(doc, f, sharedHistOnly) { - function propagate(doc, skip, sharedHist) { - if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i] - if (rel.doc == skip) { continue } - var shared = sharedHist && rel.sharedHist - if (sharedHistOnly && !shared) { continue } - f(rel.doc, shared) - propagate(rel.doc, doc, shared) - } } - } - propagate(doc, null, true) - } - - // Attach a document to an editor. - function attachDoc(cm, doc) { - if (doc.cm) { throw new Error("This document is already in use.") } - cm.doc = doc - doc.cm = cm - estimateLineHeights(cm) - loadMode(cm) - setDirectionClass(cm) - if (!cm.options.lineWrapping) { findMaxLine(cm) } - cm.options.mode = doc.modeOption - regChange(cm) - } - - function setDirectionClass(cm) { - ;(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl") - } - - function directionChanged(cm) { - runInOp(cm, function () { - setDirectionClass(cm) - regChange(cm) - }) - } - - function History(startGen) { - // Arrays of change events and selections. Doing something adds an - // event to done and clears undo. Undoing moves events from done - // to undone, redoing moves them in the other direction. - this.done = []; this.undone = [] - this.undoDepth = Infinity - // Used to track when changes can be merged into a single undo - // event - this.lastModTime = this.lastSelTime = 0 - this.lastOp = this.lastSelOp = null - this.lastOrigin = this.lastSelOrigin = null - // Used by the isClean() method - this.generation = this.maxGeneration = startGen || 1 - } - - // Create a history change event from an updateDoc-style change - // object. - function historyChangeFromChange(doc, change) { - var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} - attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) - linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true) - return histChange - } - - // Pop all selection events off the end of a history array. Stop at - // a change event. - function clearSelectionEvents(array) { - while (array.length) { - var last = lst(array) - if (last.ranges) { array.pop() } - else { break } - } - } - - // Find the top change event in the history. Pop off selection - // events that are in the way. - function lastChangeEvent(hist, force) { - if (force) { - clearSelectionEvents(hist.done) - return lst(hist.done) - } else if (hist.done.length && !lst(hist.done).ranges) { - return lst(hist.done) - } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { - hist.done.pop() - return lst(hist.done) - } - } - - // Register a change in the history. Merges changes that are within - // a single operation, or are close together with an origin that - // allows merging (starting with "+") into a single event. - function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history - hist.undone.length = 0 - var time = +new Date, cur - var last - - if ((hist.lastOp == opId || - hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) || - change.origin.charAt(0) == "*")) && - (cur = lastChangeEvent(hist, hist.lastOp == opId))) { - // Merge this change into the last event - last = lst(cur.changes) - if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { - // Optimized case for simple insertion -- don't want to add - // new changesets for every character typed - last.to = changeEnd(change) - } else { - // Add new sub-event - cur.changes.push(historyChangeFromChange(doc, change)) - } - } else { - // Can not be merged, start a new event. - var before = lst(hist.done) - if (!before || !before.ranges) - { pushSelectionToHistory(doc.sel, hist.done) } - cur = {changes: [historyChangeFromChange(doc, change)], - generation: hist.generation} - hist.done.push(cur) - while (hist.done.length > hist.undoDepth) { - hist.done.shift() - if (!hist.done[0].ranges) { hist.done.shift() } - } - } - hist.done.push(selAfter) - hist.generation = ++hist.maxGeneration - hist.lastModTime = hist.lastSelTime = time - hist.lastOp = hist.lastSelOp = opId - hist.lastOrigin = hist.lastSelOrigin = change.origin - - if (!last) { signal(doc, "historyAdded") } - } - - function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0) - return ch == "*" || - ch == "+" && - prev.ranges.length == sel.ranges.length && - prev.somethingSelected() == sel.somethingSelected() && - new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) - } - - // Called whenever the selection changes, sets the new selection as - // the pending selection in the history, and pushes the old pending - // selection into the 'done' array when it was significantly - // different (in number of selected ranges, emptiness, or time). - function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin - - // A new event is started when the previous origin does not match - // the current, or the origins don't allow matching. Origins - // starting with * are always merged, those starting with + are - // merged when similar and close together in time. - if (opId == hist.lastSelOp || - (origin && hist.lastSelOrigin == origin && - (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || - selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) - { hist.done[hist.done.length - 1] = sel } - else - { pushSelectionToHistory(sel, hist.done) } - - hist.lastSelTime = +new Date - hist.lastSelOrigin = origin - hist.lastSelOp = opId - if (options && options.clearRedo !== false) - { clearSelectionEvents(hist.undone) } - } - - function pushSelectionToHistory(sel, dest) { - var top = lst(dest) - if (!(top && top.ranges && top.equals(sel))) - { dest.push(sel) } - } - - // Used to store marked span information in the history. - function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0 - doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { - if (line.markedSpans) - { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans } - ++n - }) - } - - // When un/re-doing restores text containing marked spans, those - // that have been explicitly cleared should not be restored. - function removeClearedSpans(spans) { - if (!spans) { return null } - var out - for (var i = 0; i < spans.length; ++i) { - if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i) } } - else if (out) { out.push(spans[i]) } - } - return !out ? spans : out.length ? out : null - } - - // Retrieve and filter the old marked spans stored in a change event. - function getOldSpans(doc, change) { - var found = change["spans_" + doc.id] - if (!found) { return null } - var nw = [] - for (var i = 0; i < change.text.length; ++i) - { nw.push(removeClearedSpans(found[i])) } - return nw - } - - // Used for un/re-doing changes from the history. Combines the - // result of computing the existing spans with the set of spans that - // existed in the history (so that deleting around a span and then - // undoing brings back the span). - function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change) - var stretched = stretchSpansOverChange(doc, change) - if (!old) { return stretched } - if (!stretched) { return old } - - for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i] - if (oldCur && stretchCur) { - spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j] - for (var k = 0; k < oldCur.length; ++k) - { if (oldCur[k].marker == span.marker) { continue spans } } - oldCur.push(span) - } - } else if (stretchCur) { - old[i] = stretchCur - } - } - return old - } - - // Used both to provide a JSON-safe object in .getHistory, and, when - // detaching a document, to split the history in two - function copyHistoryArray(events, newGroup, instantiateSel) { - var copy = [] - for (var i = 0; i < events.length; ++i) { - var event = events[i] - if (event.ranges) { - copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event) - continue - } - var changes = event.changes, newChanges = [] - copy.push({changes: newChanges}) - for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m = (void 0) - newChanges.push({from: change.from, to: change.to, text: change.text}) - if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) { - if (indexOf(newGroup, Number(m[1])) > -1) { - lst(newChanges)[prop] = change[prop] - delete change[prop] - } - } } } - } - } - return copy - } - - // The 'scroll' parameter given to many of these indicated whether - // the new cursor position should be scrolled into view after - // modifying the selection. - - // If shift is held or the extend flag is set, extends a range to - // include a given position (and optionally a second position). - // Otherwise, simply returns the range between the given positions. - // Used for cursor motion and such. - function extendRange(range, head, other, extend) { - if (extend) { - var anchor = range.anchor - if (other) { - var posBefore = cmp(head, anchor) < 0 - if (posBefore != (cmp(other, anchor) < 0)) { - anchor = head - head = other - } else if (posBefore != (cmp(head, other) < 0)) { - head = other - } - } - return new Range(anchor, head) - } else { - return new Range(other || head, head) - } - } - - // Extend the primary selection range, discard the rest. - function extendSelection(doc, head, other, options, extend) { - if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend) } - setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options) - } - - // Extend all selections (pos is an array of selections with length - // equal the number of selections) - function extendSelections(doc, heads, options) { - var out = [] - var extend = doc.cm && (doc.cm.display.shift || doc.extend) - for (var i = 0; i < doc.sel.ranges.length; i++) - { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend) } - var newSel = normalizeSelection(out, doc.sel.primIndex) - setSelection(doc, newSel, options) - } - - // Updates a single range in the selection. - function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0) - ranges[i] = range - setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options) - } - - // Reset the selection to a single range. - function setSimpleSelection(doc, anchor, head, options) { - setSelection(doc, simpleSelection(anchor, head), options) - } - - // Give beforeSelectionChange handlers a change to influence a - // selection update. - function filterSelectionChange(doc, sel, options) { - var obj = { - ranges: sel.ranges, - update: function(ranges) { - var this$1 = this; - - this.ranges = [] - for (var i = 0; i < ranges.length; i++) - { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), - clipPos(doc, ranges[i].head)) } - }, - origin: options && options.origin - } - signal(doc, "beforeSelectionChange", doc, obj) - if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj) } - if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) } - else { return sel } - } - - function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done) - if (last && last.ranges) { - done[done.length - 1] = sel - setSelectionNoUndo(doc, sel, options) - } else { - setSelection(doc, sel, options) - } - } - - // Set a new selection. - function setSelection(doc, sel, options) { - setSelectionNoUndo(doc, sel, options) - addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) - } - - function setSelectionNoUndo(doc, sel, options) { - if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - { sel = filterSelectionChange(doc, sel, options) } - - var bias = options && options.bias || - (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) - setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) - - if (!(options && options.scroll === false) && doc.cm) - { ensureCursorVisible(doc.cm) } - } - - function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) { return } - - doc.sel = sel - - if (doc.cm) { - doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true - signalCursorActivity(doc.cm) - } - signalLater(doc, "cursorActivity", doc) - } - - // Verify that the selection does not partially select any atomic - // marked ranges. - function reCheckSelection(doc) { - setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false)) - } - - // Return a selection that does not partially select any atomic - // ranges. - function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i] - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) - if (out || newAnchor != range.anchor || newHead != range.head) { - if (!out) { out = sel.ranges.slice(0, i) } - out[i] = new Range(newAnchor, newHead) - } - } - return out ? normalizeSelection(out, sel.primIndex) : sel - } - - function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line) - if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && - (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { - if (mayClear) { - signal(m, "beforeCursorEnter") - if (m.explicitlyCleared) { - if (!line.markedSpans) { break } - else {--i; continue} - } - } - if (!m.atomic) { continue } - - if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff = (void 0) - if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) - { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) } - if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) - { return skipAtomicInner(doc, near, pos, dir, mayClear) } - } - - var far = m.find(dir < 0 ? -1 : 1) - if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) - { far = movePos(doc, far, dir, far.line == pos.line ? line : null) } - return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null - } - } } - return pos - } - - // Ensure a given position is not inside an atomic range. - function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1 - var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || - skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) - if (!found) { - doc.cantEdit = true - return Pos(doc.first, 0) - } - return found - } - - function movePos(doc, pos, dir, line) { - if (dir < 0 && pos.ch == 0) { - if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) } - else { return null } - } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { - if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) } - else { return null } - } else { - return new Pos(pos.line, pos.ch + dir) - } - } - - function selectAll(cm) { - cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll) - } - - // UPDATING - - // Allow "beforeChange" event handlers to influence a change - function filterChange(doc, change, update) { - var obj = { - canceled: false, - from: change.from, - to: change.to, - text: change.text, - origin: change.origin, - cancel: function () { return obj.canceled = true; } - } - if (update) { obj.update = function (from, to, text, origin) { - if (from) { obj.from = clipPos(doc, from) } - if (to) { obj.to = clipPos(doc, to) } - if (text) { obj.text = text } - if (origin !== undefined) { obj.origin = origin } - } } - signal(doc, "beforeChange", doc, obj) - if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj) } - - if (obj.canceled) { return null } - return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} - } - - // Apply a change to a document, and add it to the document's - // history, and propagating it to all linked documents. - function makeChange(doc, change, ignoreReadOnly) { - if (doc.cm) { - if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) } - if (doc.cm.state.suppressEdits) { return } - } - - if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change, true) - if (!change) { return } - } - - // Possibly split or suppress the update based on the presence - // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) - if (split) { - for (var i = split.length - 1; i >= 0; --i) - { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}) } - } else { - makeChangeInner(doc, change) - } - } - - function makeChangeInner(doc, change) { - if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return } - var selAfter = computeSelAfterChange(doc, change) - addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) - - makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) - var rebased = [] - - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change) - rebased.push(doc.history) - } - makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)) - }) - } - - // Revert a change stored in a document's history. - function makeChangeFromHistory(doc, type, allowSelectionOnly) { - var suppress = doc.cm && doc.cm.state.suppressEdits - if (suppress && !allowSelectionOnly) { return } - - var hist = doc.history, event, selAfter = doc.sel - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done - - // Verify that there is a useable event (so that ctrl-z won't - // needlessly clear selection events) - var i = 0 - for (; i < source.length; i++) { - event = source[i] - if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) - { break } - } - if (i == source.length) { return } - hist.lastOrigin = hist.lastSelOrigin = null - - for (;;) { - event = source.pop() - if (event.ranges) { - pushSelectionToHistory(event, dest) - if (allowSelectionOnly && !event.equals(doc.sel)) { - setSelection(doc, event, {clearRedo: false}) - return - } - selAfter = event - } else if (suppress) { - source.push(event) - return - } else { break } - } - - // Build up a reverse change object to add to the opposite history - // stack (redo when undoing, and vice versa). - var antiChanges = [] - pushSelectionToHistory(selAfter, dest) - dest.push({changes: antiChanges, generation: hist.generation}) - hist.generation = event.generation || ++hist.maxGeneration - - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") - - var loop = function ( i ) { - var change = event.changes[i] - change.origin = type - if (filter && !filterChange(doc, change, false)) { - source.length = 0 - return {} - } - - antiChanges.push(historyChangeFromChange(doc, change)) - - var after = i ? computeSelAfterChange(doc, change) : lst(source) - makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) - if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) } - var rebased = [] - - // Propagate to the linked documents - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change) - rebased.push(doc.history) - } - makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)) - }) - }; - - for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) { - var returned = loop( i$1 ); - - if ( returned ) return returned.v; - } - } - - // Sub-views need their line numbers shifted when text is added - // above or below them in the parent document. - function shiftDoc(doc, distance) { - if (distance == 0) { return } - doc.first += distance - doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range( - Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch) - ); }), doc.sel.primIndex) - if (doc.cm) { - regChange(doc.cm, doc.first, doc.first - distance, distance) - for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) - { regLineChange(doc.cm, l, "gutter") } - } - } - - // More lower-level change function, handling only a single document - // (not linked ones). - function makeChangeSingleDoc(doc, change, selAfter, spans) { - if (doc.cm && !doc.cm.curOp) - { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) } - - if (change.to.line < doc.first) { - shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)) - return - } - if (change.from.line > doc.lastLine()) { return } - - // Clip the change to the size of this doc - if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line) - shiftDoc(doc, shift) - change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), - text: [lst(change.text)], origin: change.origin} - } - var last = doc.lastLine() - if (change.to.line > last) { - change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), - text: [change.text[0]], origin: change.origin} - } - - change.removed = getBetween(doc, change.from, change.to) - - if (!selAfter) { selAfter = computeSelAfterChange(doc, change) } - if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans) } - else { updateDoc(doc, change, spans) } - setSelectionNoUndo(doc, selAfter, sel_dontScroll) - } - - // Handle the interaction of a change to a document with the editor - // that this document is part of. - function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to - - var recomputeMaxLength = false, checkWidthStart = from.line - if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) - doc.iter(checkWidthStart, to.line + 1, function (line) { - if (line == display.maxLine) { - recomputeMaxLength = true - return true - } - }) - } - - if (doc.sel.contains(change.from, change.to) > -1) - { signalCursorActivity(cm) } - - updateDoc(doc, change, spans, estimateHeight(cm)) - - if (!cm.options.lineWrapping) { - doc.iter(checkWidthStart, from.line + change.text.length, function (line) { - var len = lineLength(line) - if (len > display.maxLineLength) { - display.maxLine = line - display.maxLineLength = len - display.maxLineChanged = true - recomputeMaxLength = false - } - }) - if (recomputeMaxLength) { cm.curOp.updateMaxLine = true } - } - - retreatFrontier(doc, from.line) - startWorker(cm, 400) - - var lendiff = change.text.length - (to.line - from.line) - 1 - // Remember that these lines changed, for updating the display - if (change.full) - { regChange(cm) } - else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) - { regLineChange(cm, from.line, "text") } - else - { regChange(cm, from.line, to.line + 1, lendiff) } - - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") - if (changeHandler || changesHandler) { - var obj = { - from: from, to: to, - text: change.text, - removed: change.removed, - origin: change.origin - } - if (changeHandler) { signalLater(cm, "change", cm, obj) } - if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) } - } - cm.display.selForContextMenu = null - } - - function replaceRange(doc, code, from, to, origin) { - if (!to) { to = from } - if (cmp(to, from) < 0) { var assign; - (assign = [to, from], from = assign[0], to = assign[1], assign) } - if (typeof code == "string") { code = doc.splitLines(code) } - makeChange(doc, {from: from, to: to, text: code, origin: origin}) - } - - // Rebasing/resetting history to deal with externally-sourced changes - - function rebaseHistSelSingle(pos, from, to, diff) { - if (to < pos.line) { - pos.line += diff - } else if (from < pos.line) { - pos.line = from - pos.ch = 0 - } - } - - // Tries to rebase an array of history events given a change in the - // document. If the change touches the same lines as the event, the - // event, and everything 'behind' it, is discarded. If the change is - // before the event, the event's positions are updated. Uses a - // copy-on-write scheme for the positions, to avoid having to - // reallocate them all on every rebase, but also avoid problems with - // shared position objects being unsafely updated. - function rebaseHistArray(array, from, to, diff) { - for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true - if (sub.ranges) { - if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } - for (var j = 0; j < sub.ranges.length; j++) { - rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) - rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) - } - continue - } - for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) { - var cur = sub.changes[j$1] - if (to < cur.from.line) { - cur.from = Pos(cur.from.line + diff, cur.from.ch) - cur.to = Pos(cur.to.line + diff, cur.to.ch) - } else if (from <= cur.to.line) { - ok = false - break - } - } - if (!ok) { - array.splice(0, i + 1) - i = 0 - } - } - } - - function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 - rebaseHistArray(hist.done, from, to, diff) - rebaseHistArray(hist.undone, from, to, diff) - } - - // Utility for applying a change to a line by handle or number, - // returning the number and optionally registering the line as - // changed. - function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle - if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)) } - else { no = lineNo(handle) } - if (no == null) { return null } - if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType) } - return line - } - - // The document is represented as a BTree consisting of leaves, with - // chunk of lines in them, and branches, with up to ten leaves or - // other branch nodes below them. The top node is always a branch - // node, and is the document object itself (meaning it has - // additional methods and properties). - // - // All nodes have parent links. The tree is used both to go from - // line numbers to line objects, and to go from objects to numbers. - // It also indexes by height, and is used to convert between height - // and line object, and to find the total height of the document. - // - // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html - - function LeafChunk(lines) { - var this$1 = this; - - this.lines = lines - this.parent = null - var height = 0 - for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this$1 - height += lines[i].height - } - this.height = height - } - - LeafChunk.prototype = { - chunkSize: function chunkSize() { return this.lines.length }, - - // Remove the n lines at offset 'at'. - removeInner: function removeInner(at, n) { - var this$1 = this; - - for (var i = at, e = at + n; i < e; ++i) { - var line = this$1.lines[i] - this$1.height -= line.height - cleanUpLine(line) - signalLater(line, "delete") - } - this.lines.splice(at, n) - }, - - // Helper used to collapse a small branch into a single leaf. - collapse: function collapse(lines) { - lines.push.apply(lines, this.lines) - }, - - // Insert the given array of lines at offset 'at', count them as - // having the given height. - insertInner: function insertInner(at, lines, height) { - var this$1 = this; - - this.height += height - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)) - for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1 } - }, - - // Used to iterate over a part of the tree. - iterN: function iterN(at, n, op) { - var this$1 = this; - - for (var e = at + n; at < e; ++at) - { if (op(this$1.lines[at])) { return true } } - } - } - - function BranchChunk(children) { - var this$1 = this; - - this.children = children - var size = 0, height = 0 - for (var i = 0; i < children.length; ++i) { - var ch = children[i] - size += ch.chunkSize(); height += ch.height - ch.parent = this$1 - } - this.size = size - this.height = height - this.parent = null - } - - BranchChunk.prototype = { - chunkSize: function chunkSize() { return this.size }, - - removeInner: function removeInner(at, n) { - var this$1 = this; - - this.size -= n - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize() - if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height - child.removeInner(at, rm) - this$1.height -= oldHeight - child.height - if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null } - if ((n -= rm) == 0) { break } - at = 0 - } else { at -= sz } - } - // If the result is smaller than 25 lines, ensure that it is a - // single leaf node. - if (this.size - n < 25 && - (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = [] - this.collapse(lines) - this.children = [new LeafChunk(lines)] - this.children[0].parent = this - } - }, - - collapse: function collapse(lines) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines) } - }, - - insertInner: function insertInner(at, lines, height) { - var this$1 = this; - - this.size += lines.length - this.height += height - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize() - if (at <= sz) { - child.insertInner(at, lines, height) - if (child.lines && child.lines.length > 50) { - // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. - // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. - var remaining = child.lines.length % 25 + 25 - for (var pos = remaining; pos < child.lines.length;) { - var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) - child.height -= leaf.height - this$1.children.splice(++i, 0, leaf) - leaf.parent = this$1 - } - child.lines = child.lines.slice(0, remaining) - this$1.maybeSpill() - } - break - } - at -= sz - } - }, - - // When a node has grown, check whether it should be split. - maybeSpill: function maybeSpill() { - if (this.children.length <= 10) { return } - var me = this - do { - var spilled = me.children.splice(me.children.length - 5, 5) - var sibling = new BranchChunk(spilled) - if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children) - copy.parent = me - me.children = [copy, sibling] - me = copy - } else { - me.size -= sibling.size - me.height -= sibling.height - var myIndex = indexOf(me.parent.children, me) - me.parent.children.splice(myIndex + 1, 0, sibling) - } - sibling.parent = me.parent - } while (me.children.length > 10) - me.parent.maybeSpill() - }, - - iterN: function iterN(at, n, op) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize() - if (at < sz) { - var used = Math.min(n, sz - at) - if (child.iterN(at, used, op)) { return true } - if ((n -= used) == 0) { break } - at = 0 - } else { at -= sz } - } - } - } - - // Line widgets are block elements displayed above or below a line. - - var LineWidget = function(doc, node, options) { - var this$1 = this; - - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this$1[opt] = options[opt] } } } - this.doc = doc - this.node = node - }; - - LineWidget.prototype.clear = function () { - var this$1 = this; - - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) - if (no == null || !ws) { return } - for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1) } } - if (!ws.length) { line.widgets = null } - var height = widgetHeight(this) - updateLineHeight(line, Math.max(0, line.height - height)) - if (cm) { - runInOp(cm, function () { - adjustScrollWhenAboveVisible(cm, line, -height) - regLineChange(cm, no, "widget") - }) - signalLater(cm, "lineWidgetCleared", cm, this, no) - } - }; - - LineWidget.prototype.changed = function () { - var this$1 = this; - - var oldH = this.height, cm = this.doc.cm, line = this.line - this.height = null - var diff = widgetHeight(this) - oldH - if (!diff) { return } - updateLineHeight(line, line.height + diff) - if (cm) { - runInOp(cm, function () { - cm.curOp.forceUpdate = true - adjustScrollWhenAboveVisible(cm, line, diff) - signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line)) - }) - } - }; - eventMixin(LineWidget) - - function adjustScrollWhenAboveVisible(cm, line, diff) { - if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) - { addToScrollTop(cm, diff) } - } - - function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options) - var cm = doc.cm - if (cm && widget.noHScroll) { cm.display.alignWidgets = true } - changeLine(doc, handle, "widget", function (line) { - var widgets = line.widgets || (line.widgets = []) - if (widget.insertAt == null) { widgets.push(widget) } - else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) } - widget.line = line - if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop - updateLineHeight(line, line.height + widgetHeight(widget)) - if (aboveVisible) { addToScrollTop(cm, widget.height) } - cm.curOp.forceUpdate = true - } - return true - }) - if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)) } - return widget - } - - // TEXTMARKERS - - // Created with markText and setBookmark methods. A TextMarker is a - // handle that can be used to clear or find a marked position in the - // document. Line objects hold arrays (markedSpans) containing - // {from, to, marker} object pointing to such marker objects, and - // indicating that such a marker is present on that line. Multiple - // lines may point to the same marker when it spans across lines. - // The spans will have null for their from/to properties when the - // marker continues beyond the start/end of the line. Markers have - // links back to the lines they currently touch. - - // Collapsed markers have unique ids, in order to be able to order - // them, which is needed for uniquely determining an outer marker - // when they overlap (they may nest, but not partially overlap). - var nextMarkerId = 0 - - var TextMarker = function(doc, type) { - this.lines = [] - this.type = type - this.doc = doc - this.id = ++nextMarkerId - }; - - // Clear the marker. - TextMarker.prototype.clear = function () { - var this$1 = this; - - if (this.explicitlyCleared) { return } - var cm = this.doc.cm, withOp = cm && !cm.curOp - if (withOp) { startOperation(cm) } - if (hasHandler(this, "clear")) { - var found = this.find() - if (found) { signalLater(this, "clear", found.from, found.to) } - } - var min = null, max = null - for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this$1) - if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text") } - else if (cm) { - if (span.to != null) { max = lineNo(line) } - if (span.from != null) { min = lineNo(line) } - } - line.markedSpans = removeMarkedSpan(line.markedSpans, span) - if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) - { updateLineHeight(line, textHeight(cm.display)) } - } - if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { - var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual) - if (len > cm.display.maxLineLength) { - cm.display.maxLine = visual - cm.display.maxLineLength = len - cm.display.maxLineChanged = true - } - } } - - if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1) } - this.lines.length = 0 - this.explicitlyCleared = true - if (this.atomic && this.doc.cantEdit) { - this.doc.cantEdit = false - if (cm) { reCheckSelection(cm.doc) } - } - if (cm) { signalLater(cm, "markerCleared", cm, this, min, max) } - if (withOp) { endOperation(cm) } - if (this.parent) { this.parent.clear() } - }; - - // Find the position of the marker in the document. Returns a {from, - // to} object by default. Side can be passed to get a specific side - // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the - // Pos objects returned contain a line object, rather than a line - // number (used to prevent looking up the same line twice). - TextMarker.prototype.find = function (side, lineObj) { - var this$1 = this; - - if (side == null && this.type == "bookmark") { side = 1 } - var from, to - for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this$1) - if (span.from != null) { - from = Pos(lineObj ? line : lineNo(line), span.from) - if (side == -1) { return from } - } - if (span.to != null) { - to = Pos(lineObj ? line : lineNo(line), span.to) - if (side == 1) { return to } - } - } - return from && {from: from, to: to} - }; - - // Signals that the marker's widget changed, and surrounding layout - // should be recomputed. - TextMarker.prototype.changed = function () { - var this$1 = this; - - var pos = this.find(-1, true), widget = this, cm = this.doc.cm - if (!pos || !cm) { return } - runInOp(cm, function () { - var line = pos.line, lineN = lineNo(pos.line) - var view = findViewForLine(cm, lineN) - if (view) { - clearLineMeasurementCacheFor(view) - cm.curOp.selectionChanged = cm.curOp.forceUpdate = true - } - cm.curOp.updateMaxLine = true - if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height - widget.height = null - var dHeight = widgetHeight(widget) - oldHeight - if (dHeight) - { updateLineHeight(line, line.height + dHeight) } - } - signalLater(cm, "markerChanged", cm, this$1) - }) - }; - - TextMarker.prototype.attachLine = function (line) { - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp - if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) - { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) } - } - this.lines.push(line) - }; - - TextMarker.prototype.detachLine = function (line) { - this.lines.splice(indexOf(this.lines, line), 1) - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp - ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) - } - }; - eventMixin(TextMarker) - - // Create a marker, wire it up to the right lines, and - function markText(doc, from, to, options, type) { - // Shared markers (across linked documents) are handled separately - // (markTextShared will call out to this again, once per - // document). - if (options && options.shared) { return markTextShared(doc, from, to, options, type) } - // Ensure we are in an operation. - if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) } - - var marker = new TextMarker(doc, type), diff = cmp(from, to) - if (options) { copyObj(options, marker, false) } - // Don't connect empty markers unless clearWhenEmpty is false - if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) - { return marker } - if (marker.replacedWith) { - // Showing up as a widget implies collapsed (widget replaces text) - marker.collapsed = true - marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget") - if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true") } - if (options.insertLeft) { marker.widgetNode.insertLeft = true } - } - if (marker.collapsed) { - if (conflictingCollapsedRange(doc, from.line, from, to, marker) || - from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) - { throw new Error("Inserting collapsed marker partially overlapping an existing one") } - seeCollapsedSpans() - } - - if (marker.addToHistory) - { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) } - - var curLine = from.line, cm = doc.cm, updateMaxLine - doc.iter(curLine, to.line + 1, function (line) { - if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) - { updateMaxLine = true } - if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0) } - addMarkedSpan(line, new MarkedSpan(marker, - curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null)) - ++curLine - }) - // lineIsHidden depends on the presence of the spans, so needs a second pass - if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) { - if (lineIsHidden(doc, line)) { updateLineHeight(line, 0) } - }) } - - if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }) } - - if (marker.readOnly) { - seeReadOnlySpans() - if (doc.history.done.length || doc.history.undone.length) - { doc.clearHistory() } - } - if (marker.collapsed) { - marker.id = ++nextMarkerId - marker.atomic = true - } - if (cm) { - // Sync editor state - if (updateMaxLine) { cm.curOp.updateMaxLine = true } - if (marker.collapsed) - { regChange(cm, from.line, to.line + 1) } - else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) - { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text") } } - if (marker.atomic) { reCheckSelection(cm.doc) } - signalLater(cm, "markerAdded", cm, marker) - } - return marker - } - - // SHARED TEXTMARKERS - - // A shared marker spans multiple linked documents. It is - // implemented as a meta-marker-object controlling multiple normal - // markers. - var SharedTextMarker = function(markers, primary) { - var this$1 = this; - - this.markers = markers - this.primary = primary - for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this$1 } - }; - - SharedTextMarker.prototype.clear = function () { - var this$1 = this; - - if (this.explicitlyCleared) { return } - this.explicitlyCleared = true - for (var i = 0; i < this.markers.length; ++i) - { this$1.markers[i].clear() } - signalLater(this, "clear") - }; - - SharedTextMarker.prototype.find = function (side, lineObj) { - return this.primary.find(side, lineObj) - }; - eventMixin(SharedTextMarker) - - function markTextShared(doc, from, to, options, type) { - options = copyObj(options) - options.shared = false - var markers = [markText(doc, from, to, options, type)], primary = markers[0] - var widget = options.widgetNode - linkedDocs(doc, function (doc) { - if (widget) { options.widgetNode = widget.cloneNode(true) } - markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) - for (var i = 0; i < doc.linked.length; ++i) - { if (doc.linked[i].isParent) { return } } - primary = lst(markers) - }) - return new SharedTextMarker(markers, primary) - } - - function findSharedMarkers(doc) { - return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; }) - } - - function copySharedMarkers(doc, markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find() - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) - if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) - marker.markers.push(subMark) - subMark.parent = marker - } - } - } - - function detachSharedMarkers(markers) { - var loop = function ( i ) { - var marker = markers[i], linked = [marker.primary.doc] - linkedDocs(marker.primary.doc, function (d) { return linked.push(d); }) - for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j] - if (indexOf(linked, subMarker.doc) == -1) { - subMarker.parent = null - marker.markers.splice(j--, 1) - } - } - }; - - for (var i = 0; i < markers.length; i++) loop( i ); - } - - var nextDocId = 0 - var Doc = function(text, mode, firstLine, lineSep, direction) { - if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) } - if (firstLine == null) { firstLine = 0 } - - BranchChunk.call(this, [new LeafChunk([new Line("", null)])]) - this.first = firstLine - this.scrollTop = this.scrollLeft = 0 - this.cantEdit = false - this.cleanGeneration = 1 - this.modeFrontier = this.highlightFrontier = firstLine - var start = Pos(firstLine, 0) - this.sel = simpleSelection(start) - this.history = new History(null) - this.id = ++nextDocId - this.modeOption = mode - this.lineSep = lineSep - this.direction = (direction == "rtl") ? "rtl" : "ltr" - this.extend = false - - if (typeof text == "string") { text = this.splitLines(text) } - updateDoc(this, {from: start, to: start, text: text}) - setSelection(this, simpleSelection(start), sel_dontScroll) - } - - Doc.prototype = createObj(BranchChunk.prototype, { - constructor: Doc, - // Iterate over the document. Supports two forms -- with only one - // argument, it calls that for each line in the document. With - // three, it iterates over the range given by the first two (with - // the second being non-inclusive). - iter: function(from, to, op) { - if (op) { this.iterN(from - this.first, to - from, op) } - else { this.iterN(this.first, this.first + this.size, from) } - }, - - // Non-public interface for adding and removing lines. - insert: function(at, lines) { - var height = 0 - for (var i = 0; i < lines.length; ++i) { height += lines[i].height } - this.insertInner(at - this.first, lines, height) - }, - remove: function(at, n) { this.removeInner(at - this.first, n) }, - - // From here, the methods are part of the public interface. Most - // are also available from CodeMirror (editor) instances. - - getValue: function(lineSep) { - var lines = getLines(this, this.first, this.first + this.size) - if (lineSep === false) { return lines } - return lines.join(lineSep || this.lineSeparator()) - }, - setValue: docMethodOp(function(code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1 - makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), - text: this.splitLines(code), origin: "setValue", full: true}, true) - if (this.cm) { scrollToCoords(this.cm, 0, 0) } - setSelection(this, simpleSelection(top), sel_dontScroll) - }), - replaceRange: function(code, from, to, origin) { - from = clipPos(this, from) - to = to ? clipPos(this, to) : from - replaceRange(this, code, from, to, origin) - }, - getRange: function(from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)) - if (lineSep === false) { return lines } - return lines.join(lineSep || this.lineSeparator()) - }, - - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, - - getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }}, - getLineNumber: function(line) {return lineNo(line)}, - - getLineHandleVisualStart: function(line) { - if (typeof line == "number") { line = getLine(this, line) } - return visualLine(line) - }, - - lineCount: function() {return this.size}, - firstLine: function() {return this.first}, - lastLine: function() {return this.first + this.size - 1}, - - clipPos: function(pos) {return clipPos(this, pos)}, - - getCursor: function(start) { - var range = this.sel.primary(), pos - if (start == null || start == "head") { pos = range.head } - else if (start == "anchor") { pos = range.anchor } - else if (start == "end" || start == "to" || start === false) { pos = range.to() } - else { pos = range.from() } - return pos - }, - listSelections: function() { return this.sel.ranges }, - somethingSelected: function() {return this.sel.somethingSelected()}, - - setCursor: docMethodOp(function(line, ch, options) { - setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options) - }), - setSelection: docMethodOp(function(anchor, head, options) { - setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options) - }), - extendSelection: docMethodOp(function(head, other, options) { - extendSelection(this, clipPos(this, head), other && clipPos(this, other), options) - }), - extendSelections: docMethodOp(function(heads, options) { - extendSelections(this, clipPosArray(this, heads), options) - }), - extendSelectionsBy: docMethodOp(function(f, options) { - var heads = map(this.sel.ranges, f) - extendSelections(this, clipPosArray(this, heads), options) - }), - setSelections: docMethodOp(function(ranges, primary, options) { - var this$1 = this; - - if (!ranges.length) { return } - var out = [] - for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this$1, ranges[i].anchor), - clipPos(this$1, ranges[i].head)) } - if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex) } - setSelection(this, normalizeSelection(out, primary), options) - }), - addSelection: docMethodOp(function(anchor, head, options) { - var ranges = this.sel.ranges.slice(0) - ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) - setSelection(this, normalizeSelection(ranges, ranges.length - 1), options) - }), - - getSelection: function(lineSep) { - var this$1 = this; - - var ranges = this.sel.ranges, lines - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) - lines = lines ? lines.concat(sel) : sel - } - if (lineSep === false) { return lines } - else { return lines.join(lineSep || this.lineSeparator()) } - }, - getSelections: function(lineSep) { - var this$1 = this; - - var parts = [], ranges = this.sel.ranges - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()) - if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()) } - parts[i] = sel - } - return parts - }, - replaceSelection: function(code, collapse, origin) { - var dup = [] - for (var i = 0; i < this.sel.ranges.length; i++) - { dup[i] = code } - this.replaceSelections(dup, collapse, origin || "+input") - }, - replaceSelections: docMethodOp(function(code, collapse, origin) { - var this$1 = this; - - var changes = [], sel = this.sel - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i] - changes[i] = {from: range.from(), to: range.to(), text: this$1.splitLines(code[i]), origin: origin} - } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) - for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) - { makeChange(this$1, changes[i$1]) } - if (newSel) { setSelectionReplaceHistory(this, newSel) } - else if (this.cm) { ensureCursorVisible(this.cm) } - }), - undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}), - redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}), - undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}), - redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}), - - setExtending: function(val) {this.extend = val}, - getExtending: function() {return this.extend}, - - historySize: function() { - var hist = this.history, done = 0, undone = 0 - for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done } } - for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone } } - return {undo: done, redo: undone} - }, - clearHistory: function() {this.history = new History(this.history.maxGeneration)}, - - markClean: function() { - this.cleanGeneration = this.changeGeneration(true) - }, - changeGeneration: function(forceSplit) { - if (forceSplit) - { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null } - return this.history.generation - }, - isClean: function (gen) { - return this.history.generation == (gen || this.cleanGeneration) - }, - - getHistory: function() { - return {done: copyHistoryArray(this.history.done), - undone: copyHistoryArray(this.history.undone)} - }, - setHistory: function(histData) { - var hist = this.history = new History(this.history.maxGeneration) - hist.done = copyHistoryArray(histData.done.slice(0), null, true) - hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) - }, - - setGutterMarker: docMethodOp(function(line, gutterID, value) { - return changeLine(this, line, "gutter", function (line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}) - markers[gutterID] = value - if (!value && isEmpty(markers)) { line.gutterMarkers = null } - return true - }) - }), - - clearGutter: docMethodOp(function(gutterID) { - var this$1 = this; - - this.iter(function (line) { - if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - changeLine(this$1, line, "gutter", function () { - line.gutterMarkers[gutterID] = null - if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null } - return true - }) - } - }) - }), - - lineInfo: function(line) { - var n - if (typeof line == "number") { - if (!isLine(this, line)) { return null } - n = line - line = getLine(this, line) - if (!line) { return null } - } else { - n = lineNo(line) - if (n == null) { return null } - } - return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets} - }, - - addLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass" - if (!line[prop]) { line[prop] = cls } - else if (classTest(cls).test(line[prop])) { return false } - else { line[prop] += " " + cls } - return true - }) - }), - removeLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass" - var cur = line[prop] - if (!cur) { return false } - else if (cls == null) { line[prop] = null } - else { - var found = cur.match(classTest(cls)) - if (!found) { return false } - var end = found.index + found[0].length - line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null - } - return true - }) - }), - - addLineWidget: docMethodOp(function(handle, node, options) { - return addLineWidget(this, handle, node, options) - }), - removeLineWidget: function(widget) { widget.clear() }, - - markText: function(from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") - }, - setBookmark: function(pos, options) { - var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), - insertLeft: options && options.insertLeft, - clearWhenEmpty: false, shared: options && options.shared, - handleMouseEvents: options && options.handleMouseEvents} - pos = clipPos(this, pos) - return markText(this, pos, pos, realOpts, "bookmark") - }, - findMarksAt: function(pos) { - pos = clipPos(this, pos) - var markers = [], spans = getLine(this, pos.line).markedSpans - if (spans) { for (var i = 0; i < spans.length; ++i) { - var span = spans[i] - if ((span.from == null || span.from <= pos.ch) && - (span.to == null || span.to >= pos.ch)) - { markers.push(span.marker.parent || span.marker) } - } } - return markers - }, - findMarks: function(from, to, filter) { - from = clipPos(this, from); to = clipPos(this, to) - var found = [], lineNo = from.line - this.iter(from.line, to.line + 1, function (line) { - var spans = line.markedSpans - if (spans) { for (var i = 0; i < spans.length; i++) { - var span = spans[i] - if (!(span.to != null && lineNo == from.line && from.ch >= span.to || - span.from == null && lineNo != from.line || - span.from != null && lineNo == to.line && span.from >= to.ch) && - (!filter || filter(span.marker))) - { found.push(span.marker.parent || span.marker) } - } } - ++lineNo - }) - return found - }, - getAllMarks: function() { - var markers = [] - this.iter(function (line) { - var sps = line.markedSpans - if (sps) { for (var i = 0; i < sps.length; ++i) - { if (sps[i].from != null) { markers.push(sps[i].marker) } } } - }) - return markers - }, - - posFromIndex: function(off) { - var ch, lineNo = this.first, sepSize = this.lineSeparator().length - this.iter(function (line) { - var sz = line.text.length + sepSize - if (sz > off) { ch = off; return true } - off -= sz - ++lineNo - }) - return clipPos(this, Pos(lineNo, ch)) - }, - indexFromPos: function (coords) { - coords = clipPos(this, coords) - var index = coords.ch - if (coords.line < this.first || coords.ch < 0) { return 0 } - var sepSize = this.lineSeparator().length - this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value - index += line.text.length + sepSize - }) - return index - }, - - copy: function(copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), - this.modeOption, this.first, this.lineSep, this.direction) - doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft - doc.sel = this.sel - doc.extend = false - if (copyHistory) { - doc.history.undoDepth = this.history.undoDepth - doc.setHistory(this.getHistory()) - } - return doc - }, - - linkedDoc: function(options) { - if (!options) { options = {} } - var from = this.first, to = this.first + this.size - if (options.from != null && options.from > from) { from = options.from } - if (options.to != null && options.to < to) { to = options.to } - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction) - if (options.sharedHist) { copy.history = this.history - ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) - copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] - copySharedMarkers(copy, findSharedMarkers(this)) - return copy - }, - unlinkDoc: function(other) { - var this$1 = this; - - if (other instanceof CodeMirror) { other = other.doc } - if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this$1.linked[i] - if (link.doc != other) { continue } - this$1.linked.splice(i, 1) - other.unlinkDoc(this$1) - detachSharedMarkers(findSharedMarkers(this$1)) - break - } } - // If the histories were shared, split them again - if (other.history == this.history) { - var splitIds = [other.id] - linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true) - other.history = new History(null) - other.history.done = copyHistoryArray(this.history.done, splitIds) - other.history.undone = copyHistoryArray(this.history.undone, splitIds) - } - }, - iterLinkedDocs: function(f) {linkedDocs(this, f)}, - - getMode: function() {return this.mode}, - getEditor: function() {return this.cm}, - - splitLines: function(str) { - if (this.lineSep) { return str.split(this.lineSep) } - return splitLinesAuto(str) - }, - lineSeparator: function() { return this.lineSep || "\n" }, - - setDirection: docMethodOp(function (dir) { - if (dir != "rtl") { dir = "ltr" } - if (dir == this.direction) { return } - this.direction = dir - this.iter(function (line) { return line.order = null; }) - if (this.cm) { directionChanged(this.cm) } - }) - }) - - // Public alias. - Doc.prototype.eachLine = Doc.prototype.iter - - // Kludge to work around strange IE behavior where it'll sometimes - // re-fire a series of drag-related events right after the drop (#1551) - var lastDrop = 0 - - function onDrop(e) { - var cm = this - clearDragCursor(cm) - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) - { return } - e_preventDefault(e) - if (ie) { lastDrop = +new Date } - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files - if (!pos || cm.isReadOnly()) { return } - // Might be a file drop, in which case we simply extract the text - // and insert it. - if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0 - var loadFile = function (file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) - { return } - - var reader = new FileReader - reader.onload = operation(cm, function () { - var content = reader.result - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = "" } - text[i] = content - if (++read == n) { - pos = clipPos(cm.doc, pos) - var change = {from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), - origin: "paste"} - makeChange(cm.doc, change) - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) - } - }) - reader.readAsText(file) - } - for (var i = 0; i < n; ++i) { loadFile(files[i], i) } - } else { // Normal drop - // Don't do a replace if the drop happened inside of the selected text. - if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { - cm.state.draggingText(e) - // Ensure the editor is re-focused - setTimeout(function () { return cm.display.input.focus(); }, 20) - return - } - try { - var text$1 = e.dataTransfer.getData("Text") - if (text$1) { - var selected - if (cm.state.draggingText && !cm.state.draggingText.copy) - { selected = cm.listSelections() } - setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) - if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1) - { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag") } } - cm.replaceSelection(text$1, "around", "paste") - cm.display.input.focus() - } - } - catch(e){} - } - } - - function onDragStart(cm, e) { - if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return } - - e.dataTransfer.setData("Text", cm.getSelection()) - e.dataTransfer.effectAllowed = "copyMove" - - // Use dummy image instead of default browsers image. - // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. - if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;") - img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" - if (presto) { - img.width = img.height = 1 - cm.display.wrapper.appendChild(img) - // Force a relayout, or Opera won't use our image for some obscure reason - img._top = img.offsetTop - } - e.dataTransfer.setDragImage(img, 0, 0) - if (presto) { img.parentNode.removeChild(img) } - } - } - - function onDragOver(cm, e) { - var pos = posFromMouse(cm, e) - if (!pos) { return } - var frag = document.createDocumentFragment() - drawSelectionCursor(cm, pos, frag) - if (!cm.display.dragCursor) { - cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") - cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) - } - removeChildrenAndAdd(cm.display.dragCursor, frag) - } - - function clearDragCursor(cm) { - if (cm.display.dragCursor) { - cm.display.lineSpace.removeChild(cm.display.dragCursor) - cm.display.dragCursor = null - } - } - - // These must be handled carefully, because naively registering a - // handler for each editor will cause the editors to never be - // garbage collected. - - function forEachCodeMirror(f) { - if (!document.getElementsByClassName) { return } - var byClass = document.getElementsByClassName("CodeMirror") - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror - if (cm) { f(cm) } - } - } - - var globalsRegistered = false - function ensureGlobalHandlers() { - if (globalsRegistered) { return } - registerGlobalHandlers() - globalsRegistered = true - } - function registerGlobalHandlers() { - // When the window resizes, we need to refresh active editors. - var resizeTimer - on(window, "resize", function () { - if (resizeTimer == null) { resizeTimer = setTimeout(function () { - resizeTimer = null - forEachCodeMirror(onResize) - }, 100) } - }) - // When the window loses focus, we want to show the editor as blurred - on(window, "blur", function () { return forEachCodeMirror(onBlur); }) - } - // Called when the window resizes - function onResize(cm) { - var d = cm.display - if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) - { return } - // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null - d.scrollbarsClipped = false - cm.setSize() - } - - var keyNames = { - 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", - 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", - 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", - 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" - } - - // Number keys - for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i) } - // Alphabetic keys - for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1) } - // Function keys - for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2 } - - var keyMap = {} - - keyMap.basic = { - "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", - "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", - "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", - "Tab": "defaultTab", "Shift-Tab": "indentAuto", - "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", - "Esc": "singleSelection" - } - // Note that the save and find-related commands aren't defined by - // default. User code or addons can define them. Unknown commands - // are simply ignored. - keyMap.pcDefault = { - "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", - "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", - "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", - "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", - "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", - "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", - fallthrough: "basic" - } - // Very basic readline/emacs-style bindings, which are standard on Mac. - keyMap.emacsy = { - "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", - "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", - "Ctrl-O": "openLine" - } - keyMap.macDefault = { - "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", - "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", - "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", - "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", - "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", - "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", - fallthrough: ["basic", "emacsy"] - } - keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault - - // KEYMAP DISPATCH - - function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/) - name = parts[parts.length - 1] - var alt, ctrl, shift, cmd - for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i] - if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true } - else if (/^a(lt)?$/i.test(mod)) { alt = true } - else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true } - else if (/^s(hift)?$/i.test(mod)) { shift = true } - else { throw new Error("Unrecognized modifier name: " + mod) } - } - if (alt) { name = "Alt-" + name } - if (ctrl) { name = "Ctrl-" + name } - if (cmd) { name = "Cmd-" + name } - if (shift) { name = "Shift-" + name } - return name - } - - // This is a kludge to keep keymaps mostly working as raw objects - // (backwards compatibility) while at the same time support features - // like normalization and multi-stroke key bindings. It compiles a - // new normalized keymap, and then updates the old object to reflect - // this. - function normalizeKeyMap(keymap) { - var copy = {} - for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname] - if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue } - if (value == "...") { delete keymap[keyname]; continue } - - var keys = map(keyname.split(" "), normalizeKeyName) - for (var i = 0; i < keys.length; i++) { - var val = (void 0), name = (void 0) - if (i == keys.length - 1) { - name = keys.join(" ") - val = value - } else { - name = keys.slice(0, i + 1).join(" ") - val = "..." - } - var prev = copy[name] - if (!prev) { copy[name] = val } - else if (prev != val) { throw new Error("Inconsistent bindings for " + name) } - } - delete keymap[keyname] - } } - for (var prop in copy) { keymap[prop] = copy[prop] } - return keymap - } - - function lookupKey(key, map, handle, context) { - map = getKeyMap(map) - var found = map.call ? map.call(key, context) : map[key] - if (found === false) { return "nothing" } - if (found === "...") { return "multi" } - if (found != null && handle(found)) { return "handled" } - - if (map.fallthrough) { - if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") - { return lookupKey(key, map.fallthrough, handle, context) } - for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context) - if (result) { return result } - } - } - } - - // Modifier key presses don't count as 'real' key presses for the - // purpose of keymap fallthrough. - function isModifierKey(value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode] - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" - } - - function addModifierNames(name, event, noShift) { - var base = name - if (event.altKey && base != "Alt") { name = "Alt-" + name } - if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name } - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name } - if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name } - return name - } - - // Look up the name of a key as indicated by an event object. - function keyName(event, noShift) { - if (presto && event.keyCode == 34 && event["char"]) { return false } - var name = keyNames[event.keyCode] - if (name == null || event.altGraphKey) { return false } - // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, - // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) - if (event.keyCode == 3 && event.code) { name = event.code } - return addModifierNames(name, event, noShift) - } - - function getKeyMap(val) { - return typeof val == "string" ? keyMap[val] : val - } - - // Helper for deleting text near the selection(s), used to implement - // backspace, delete, and similar functionality. - function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = [] - // Build up a set of ranges to kill first, merging overlapping - // ranges. - for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]) - while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop() - if (cmp(replaced.from, toKill.from) < 0) { - toKill.from = replaced.from - break - } - } - kill.push(toKill) - } - // Next, remove those actual ranges. - runInOp(cm, function () { - for (var i = kill.length - 1; i >= 0; i--) - { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") } - ensureCursorVisible(cm) - }) - } - - function moveCharLogically(line, ch, dir) { - var target = skipExtendingChars(line.text, ch + dir, dir) - return target < 0 || target > line.text.length ? null : target - } - - function moveLogically(line, start, dir) { - var ch = moveCharLogically(line, start.ch, dir) - return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before") - } - - function endOfLine(visually, cm, lineObj, lineNo, dir) { - if (visually) { - var order = getOrder(lineObj, cm.doc.direction) - if (order) { - var part = dir < 0 ? lst(order) : order[0] - var moveInStorageOrder = (dir < 0) == (part.level == 1) - var sticky = moveInStorageOrder ? "after" : "before" - var ch - // With a wrapped rtl chunk (possibly spanning multiple bidi parts), - // it could be that the last bidi part is not on the last visual line, - // since visual lines contain content order-consecutive chunks. - // Thus, in rtl, we are looking for the first (content-order) character - // in the rtl chunk that is on the last line (that is, the same line - // as the last (content-order) character). - if (part.level > 0 || cm.doc.direction == "rtl") { - var prep = prepareMeasureForLine(cm, lineObj) - ch = dir < 0 ? lineObj.text.length - 1 : 0 - var targetTop = measureCharPrepared(cm, prep, ch).top - ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch) - if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1) } - } else { ch = dir < 0 ? part.to : part.from } - return new Pos(lineNo, ch, sticky) - } - } - return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after") - } - - function moveVisually(cm, line, start, dir) { - var bidi = getOrder(line, cm.doc.direction) - if (!bidi) { return moveLogically(line, start, dir) } - if (start.ch >= line.text.length) { - start.ch = line.text.length - start.sticky = "before" - } else if (start.ch <= 0) { - start.ch = 0 - start.sticky = "after" - } - var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos] - if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { - // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, - // nothing interesting happens. - return moveLogically(line, start, dir) - } - - var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); } - var prep - var getWrappedLineExtent = function (ch) { - if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} } - prep = prep || prepareMeasureForLine(cm, line) - return wrappedLineExtentChar(cm, line, prep, ch) - } - var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch) - - if (cm.doc.direction == "rtl" || part.level == 1) { - var moveInStorageOrder = (part.level == 1) == (dir < 0) - var ch = mv(start, moveInStorageOrder ? 1 : -1) - if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { - // Case 2: We move within an rtl part or in an rtl editor on the same visual line - var sticky = moveInStorageOrder ? "before" : "after" - return new Pos(start.line, ch, sticky) - } - } - - // Case 3: Could not move within this bidi part in this visual line, so leave - // the current bidi part - - var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { - var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder - ? new Pos(start.line, mv(ch, 1), "before") - : new Pos(start.line, ch, "after"); } - - for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { - var part = bidi[partPos] - var moveInStorageOrder = (dir > 0) == (part.level != 1) - var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1) - if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) } - ch = moveInStorageOrder ? part.from : mv(part.to, -1) - if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) } - } - } - - // Case 3a: Look for other bidi parts on the same visual line - var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent) - if (res) { return res } - - // Case 3b: Look for other bidi parts on the next visual line - var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1) - if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) { - res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh)) - if (res) { return res } - } - - // Case 4: Nowhere to move - return null - } - - // Commands are parameter-less actions that can be performed on an - // editor, mostly used for keybindings. - var commands = { - selectAll: selectAll, - singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, - killLine: function (cm) { return deleteNearSelection(cm, function (range) { - if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length - if (range.head.ch == len && range.head.line < cm.lastLine()) - { return {from: range.head, to: Pos(range.head.line + 1, 0)} } - else - { return {from: range.head, to: Pos(range.head.line, len)} } - } else { - return {from: range.from(), to: range.to()} - } - }); }, - deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({ - from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) - }); }); }, - delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({ - from: Pos(range.from().line, 0), to: range.from() - }); }); }, - delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5 - var leftPos = cm.coordsChar({left: 0, top: top}, "div") - return {from: leftPos, to: range.from()} - }); }, - delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5 - var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") - return {from: range.from(), to: rightPos } - }); }, - undo: function (cm) { return cm.undo(); }, - redo: function (cm) { return cm.redo(); }, - undoSelection: function (cm) { return cm.undoSelection(); }, - redoSelection: function (cm) { return cm.redoSelection(); }, - goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); }, - goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); }, - goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, - {origin: "+move", bias: 1} - ); }, - goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); }, - {origin: "+move", bias: 1} - ); }, - goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, - {origin: "+move", bias: -1} - ); }, - goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5 - return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") - }, sel_move); }, - goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5 - return cm.coordsChar({left: 0, top: top}, "div") - }, sel_move); }, - goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) { - var top = cm.cursorCoords(range.head, "div").top + 5 - var pos = cm.coordsChar({left: 0, top: top}, "div") - if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) } - return pos - }, sel_move); }, - goLineUp: function (cm) { return cm.moveV(-1, "line"); }, - goLineDown: function (cm) { return cm.moveV(1, "line"); }, - goPageUp: function (cm) { return cm.moveV(-1, "page"); }, - goPageDown: function (cm) { return cm.moveV(1, "page"); }, - goCharLeft: function (cm) { return cm.moveH(-1, "char"); }, - goCharRight: function (cm) { return cm.moveH(1, "char"); }, - goColumnLeft: function (cm) { return cm.moveH(-1, "column"); }, - goColumnRight: function (cm) { return cm.moveH(1, "column"); }, - goWordLeft: function (cm) { return cm.moveH(-1, "word"); }, - goGroupRight: function (cm) { return cm.moveH(1, "group"); }, - goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, - goWordRight: function (cm) { return cm.moveH(1, "word"); }, - delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, - delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, - delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, - delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, - delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); }, - delGroupAfter: function (cm) { return cm.deleteH(1, "group"); }, - indentAuto: function (cm) { return cm.indentSelection("smart"); }, - indentMore: function (cm) { return cm.indentSelection("add"); }, - indentLess: function (cm) { return cm.indentSelection("subtract"); }, - insertTab: function (cm) { return cm.replaceSelection("\t"); }, - insertSoftTab: function (cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize - for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from() - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) - spaces.push(spaceStr(tabSize - col % tabSize)) - } - cm.replaceSelections(spaces) - }, - defaultTab: function (cm) { - if (cm.somethingSelected()) { cm.indentSelection("add") } - else { cm.execCommand("insertTab") } - }, - // Swap the two chars left and right of each selection's head. - // Move cursor behind the two swapped characters afterwards. - // - // Doesn't consider line feeds a character. - // Doesn't scan more than one line above to find a character. - // Doesn't do anything on an empty line. - // Doesn't do anything with non-empty selections. - transposeChars: function (cm) { return runInOp(cm, function () { - var ranges = cm.listSelections(), newSel = [] - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) { continue } - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text - if (line) { - if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1) } - if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1) - cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose") - } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text - if (prev) { - cur = new Pos(cur.line, 1) - cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + - prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), cur, "+transpose") - } - } - } - newSel.push(new Range(cur, cur)) - } - cm.setSelections(newSel) - }); }, - newlineAndIndent: function (cm) { return runInOp(cm, function () { - var sels = cm.listSelections() - for (var i = sels.length - 1; i >= 0; i--) - { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") } - sels = cm.listSelections() - for (var i$1 = 0; i$1 < sels.length; i$1++) - { cm.indentLine(sels[i$1].from().line, null, true) } - ensureCursorVisible(cm) - }); }, - openLine: function (cm) { return cm.replaceSelection("\n", "start"); }, - toggleOverwrite: function (cm) { return cm.toggleOverwrite(); } - } - - - function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN) - var visual = visualLine(line) - if (visual != line) { lineN = lineNo(visual) } - return endOfLine(true, cm, visual, lineN, 1) - } - function lineEnd(cm, lineN) { - var line = getLine(cm.doc, lineN) - var visual = visualLineEnd(line) - if (visual != line) { lineN = lineNo(visual) } - return endOfLine(true, cm, line, lineN, -1) - } - function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line) - var line = getLine(cm.doc, start.line) - var order = getOrder(line, cm.doc.direction) - if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)) - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch - return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) - } - return start - } - - // Run a handler that was bound to a key. - function doHandleBinding(cm, bound, dropShift) { - if (typeof bound == "string") { - bound = commands[bound] - if (!bound) { return false } - } - // Ensure previous input has been read, so that the handler sees a - // consistent view of the document - cm.display.input.ensurePolled() - var prevShift = cm.display.shift, done = false - try { - if (cm.isReadOnly()) { cm.state.suppressEdits = true } - if (dropShift) { cm.display.shift = false } - done = bound(cm) != Pass - } finally { - cm.display.shift = prevShift - cm.state.suppressEdits = false - } - return done - } - - function lookupKeyForEditor(cm, name, handle) { - for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm) - if (result) { return result } - } - return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) - || lookupKey(name, cm.options.keyMap, handle, cm) - } - - // Note that, despite the name, this function is also used to check - // for bound mouse clicks. - - var stopSeq = new Delayed - - function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq - if (seq) { - if (isModifierKey(name)) { return "handled" } - if (/\'$/.test(name)) - { cm.state.keySeq = null } - else - { stopSeq.set(50, function () { - if (cm.state.keySeq == seq) { - cm.state.keySeq = null - cm.display.input.reset() - } - }) } - if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true } - } - return dispatchKeyInner(cm, name, e, handle) - } - - function dispatchKeyInner(cm, name, e, handle) { - var result = lookupKeyForEditor(cm, name, handle) - - if (result == "multi") - { cm.state.keySeq = name } - if (result == "handled") - { signalLater(cm, "keyHandled", cm, name, e) } - - if (result == "handled" || result == "multi") { - e_preventDefault(e) - restartBlink(cm) - } - - return !!result - } - - // Handle a key from the keydown event. - function handleKeyBinding(cm, e) { - var name = keyName(e, true) - if (!name) { return false } - - if (e.shiftKey && !cm.state.keySeq) { - // First try to resolve full name (including 'Shift-'). Failing - // that, see if there is a cursor-motion command (starting with - // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) - || dispatchKey(cm, name, e, function (b) { - if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) - { return doHandleBinding(cm, b) } - }) - } else { - return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }) - } - } - - // Handle a key from the keypress event - function handleCharBinding(cm, e, ch) { - return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); }) - } - - var lastStoppedKey = null - function onKeyDown(e) { - var cm = this - cm.curOp.focus = activeElt() - if (signalDOMEvent(cm, e)) { return } - // IE does strange things with escape. - if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false } - var code = e.keyCode - cm.display.shift = code == 16 || e.shiftKey - var handled = handleKeyBinding(cm, e) - if (presto) { - lastStoppedKey = handled ? code : null - // Opera has no cut event... we try to at least catch the key combo - if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) - { cm.replaceSelection("", null, "cut") } - } - - // Turn mouse into crosshair when Alt is held on Mac. - if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) - { showCrossHair(cm) } - } - - function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv - addClass(lineDiv, "CodeMirror-crosshair") - - function up(e) { - if (e.keyCode == 18 || !e.altKey) { - rmClass(lineDiv, "CodeMirror-crosshair") - off(document, "keyup", up) - off(document, "mouseover", up) - } - } - on(document, "keyup", up) - on(document, "mouseover", up) - } - - function onKeyUp(e) { - if (e.keyCode == 16) { this.doc.sel.shift = false } - signalDOMEvent(this, e) - } - - function onKeyPress(e) { - var cm = this - if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } - var keyCode = e.keyCode, charCode = e.charCode - if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} - if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return } - var ch = String.fromCharCode(charCode == null ? keyCode : charCode) - // Some browsers fire keypress events for backspace - if (ch == "\x08") { return } - if (handleCharBinding(cm, e, ch)) { return } - cm.display.input.onKeyPress(e) - } - - var DOUBLECLICK_DELAY = 400 - - var PastClick = function(time, pos, button) { - this.time = time - this.pos = pos - this.button = button - }; - - PastClick.prototype.compare = function (time, pos, button) { - return this.time + DOUBLECLICK_DELAY > time && - cmp(pos, this.pos) == 0 && button == this.button - }; - - var lastClick; - var lastDoubleClick; - function clickRepeat(pos, button) { - var now = +new Date - if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) { - lastClick = lastDoubleClick = null - return "triple" - } else if (lastClick && lastClick.compare(now, pos, button)) { - lastDoubleClick = new PastClick(now, pos, button) - lastClick = null - return "double" - } else { - lastClick = new PastClick(now, pos, button) - lastDoubleClick = null - return "single" - } - } - - // A mouse down can be a single click, double click, triple click, - // start of selection drag, start of text drag, new cursor - // (ctrl-click), rectangle drag (alt-drag), or xwin - // middle-click-paste. Or it might be a click on something we should - // not interfere with, such as a scrollbar or widget. - function onMouseDown(e) { - var cm = this, display = cm.display - if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return } - display.input.ensurePolled() - display.shift = e.shiftKey - - if (eventInWidget(display, e)) { - if (!webkit) { - // Briefly turn off draggability, to allow widgets to do - // normal dragging things. - display.scroller.draggable = false - setTimeout(function () { return display.scroller.draggable = true; }, 100) - } - return - } - if (clickInGutter(cm, e)) { return } - var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single" - window.focus() - - // #3261: make sure, that we're not starting a second selection - if (button == 1 && cm.state.selectingText) - { cm.state.selectingText(e) } - - if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return } - - if (button == 1) { - if (pos) { leftButtonDown(cm, pos, repeat, e) } - else if (e_target(e) == display.scroller) { e_preventDefault(e) } - } else if (button == 2) { - if (pos) { extendSelection(cm.doc, pos) } - setTimeout(function () { return display.input.focus(); }, 20) - } else if (button == 3) { - if (captureRightClick) { onContextMenu(cm, e) } - else { delayBlurEvent(cm) } - } - } - - function handleMappedButton(cm, button, pos, repeat, event) { - var name = "Click" - if (repeat == "double") { name = "Double" + name } - else if (repeat == "triple") { name = "Triple" + name } - name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name - - return dispatchKey(cm, addModifierNames(name, event), event, function (bound) { - if (typeof bound == "string") { bound = commands[bound] } - if (!bound) { return false } - var done = false - try { - if (cm.isReadOnly()) { cm.state.suppressEdits = true } - done = bound(cm, pos) != Pass - } finally { - cm.state.suppressEdits = false - } - return done - }) - } - - function configureMouse(cm, repeat, event) { - var option = cm.getOption("configureMouse") - var value = option ? option(cm, repeat, event) : {} - if (value.unit == null) { - var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey - value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line" - } - if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey } - if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey } - if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey) } - return value - } - - function leftButtonDown(cm, pos, repeat, event) { - if (ie) { setTimeout(bind(ensureFocus, cm), 0) } - else { cm.curOp.focus = activeElt() } - - var behavior = configureMouse(cm, repeat, event) - - var sel = cm.doc.sel, contained - if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && - repeat == "single" && (contained = sel.contains(pos)) > -1 && - (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) && - (cmp(contained.to(), pos) > 0 || pos.xRel < 0)) - { leftButtonStartDrag(cm, event, pos, behavior) } - else - { leftButtonSelect(cm, event, pos, behavior) } - } - - // Start a text drag. When it ends, see if any dragging actually - // happen, and treat as a click if it didn't. - function leftButtonStartDrag(cm, event, pos, behavior) { - var display = cm.display, moved = false - var dragEnd = operation(cm, function (e) { - if (webkit) { display.scroller.draggable = false } - cm.state.draggingText = false - off(display.wrapper.ownerDocument, "mouseup", dragEnd) - off(display.wrapper.ownerDocument, "mousemove", mouseMove) - off(display.scroller, "dragstart", dragStart) - off(display.scroller, "drop", dragEnd) - if (!moved) { - e_preventDefault(e) - if (!behavior.addNew) - { extendSelection(cm.doc, pos, null, null, behavior.extend) } - // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus()}, 20) } - else - { display.input.focus() } - } - }) - var mouseMove = function(e2) { - moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10 - } - var dragStart = function () { return moved = true; } - // Let the drag handler handle this. - if (webkit) { display.scroller.draggable = true } - cm.state.draggingText = dragEnd - dragEnd.copy = !behavior.moveOnDrag - // IE's approach to draggable - if (display.scroller.dragDrop) { display.scroller.dragDrop() } - on(display.wrapper.ownerDocument, "mouseup", dragEnd) - on(display.wrapper.ownerDocument, "mousemove", mouseMove) - on(display.scroller, "dragstart", dragStart) - on(display.scroller, "drop", dragEnd) - - delayBlurEvent(cm) - setTimeout(function () { return display.input.focus(); }, 20) - } - - function rangeForUnit(cm, pos, unit) { - if (unit == "char") { return new Range(pos, pos) } - if (unit == "word") { return cm.findWordAt(pos) } - if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } - var result = unit(cm, pos) - return new Range(result.from, result.to) - } - - // Normal selection, as opposed to text dragging. - function leftButtonSelect(cm, event, start, behavior) { - var display = cm.display, doc = cm.doc - e_preventDefault(event) - - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges - if (behavior.addNew && !behavior.extend) { - ourIndex = doc.sel.contains(start) - if (ourIndex > -1) - { ourRange = ranges[ourIndex] } - else - { ourRange = new Range(start, start) } - } else { - ourRange = doc.sel.primary() - ourIndex = doc.sel.primIndex - } - - if (behavior.unit == "rectangle") { - if (!behavior.addNew) { ourRange = new Range(start, start) } - start = posFromMouse(cm, event, true, true) - ourIndex = -1 - } else { - var range = rangeForUnit(cm, start, behavior.unit) - if (behavior.extend) - { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend) } - else - { ourRange = range } - } - - if (!behavior.addNew) { - ourIndex = 0 - setSelection(doc, new Selection([ourRange], 0), sel_mouse) - startSel = doc.sel - } else if (ourIndex == -1) { - ourIndex = ranges.length - setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), - {scroll: false, origin: "*mouse"}) - } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { - setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), - {scroll: false, origin: "*mouse"}) - startSel = doc.sel - } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse) - } - - var lastPos = start - function extendTo(pos) { - if (cmp(lastPos, pos) == 0) { return } - lastPos = pos - - if (behavior.unit == "rectangle") { - var ranges = [], tabSize = cm.options.tabSize - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) - for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); - line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) - if (left == right) - { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) } - else if (text.length > leftPos) - { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))) } - } - if (!ranges.length) { ranges.push(new Range(start, start)) } - setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), - {origin: "*mouse", scroll: false}) - cm.scrollIntoView(pos) - } else { - var oldRange = ourRange - var range = rangeForUnit(cm, pos, behavior.unit) - var anchor = oldRange.anchor, head - if (cmp(range.anchor, anchor) > 0) { - head = range.head - anchor = minPos(oldRange.from(), range.anchor) - } else { - head = range.anchor - anchor = maxPos(oldRange.to(), range.head) - } - var ranges$1 = startSel.ranges.slice(0) - ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)) - setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse) - } - } - - var editorSize = display.wrapper.getBoundingClientRect() - // Used to ensure timeout re-tries don't fire when another extend - // happened in the meantime (clearTimeout isn't reliable -- at - // least on Chrome, the timeouts still happen even when cleared, - // if the clear happens after their scheduled firing time). - var counter = 0 - - function extend(e) { - var curCount = ++counter - var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle") - if (!cur) { return } - if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt() - extendTo(cur) - var visible = visibleLines(display, doc) - if (cur.line >= visible.to || cur.line < visible.from) - { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e) }}), 150) } - } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 - if (outside) { setTimeout(operation(cm, function () { - if (counter != curCount) { return } - display.scroller.scrollTop += outside - extend(e) - }), 50) } - } - } - - function done(e) { - cm.state.selectingText = false - counter = Infinity - e_preventDefault(e) - display.input.focus() - off(display.wrapper.ownerDocument, "mousemove", move) - off(display.wrapper.ownerDocument, "mouseup", up) - doc.history.lastSelOrigin = null - } - - var move = operation(cm, function (e) { - if (!e_button(e)) { done(e) } - else { extend(e) } - }) - var up = operation(cm, done) - cm.state.selectingText = up - on(display.wrapper.ownerDocument, "mousemove", move) - on(display.wrapper.ownerDocument, "mouseup", up) - } - - // Used when mouse-selecting to adjust the anchor to the proper side - // of a bidi jump depending on the visual position of the head. - function bidiSimplify(cm, range) { - var anchor = range.anchor; - var head = range.head; - var anchorLine = getLine(cm.doc, anchor.line) - if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } - var order = getOrder(anchorLine) - if (!order) { return range } - var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index] - if (part.from != anchor.ch && part.to != anchor.ch) { return range } - var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1) - if (boundary == 0 || boundary == order.length) { return range } - - // Compute the relative visual position of the head compared to the - // anchor (<0 is to the left, >0 to the right) - var leftSide - if (head.line != anchor.line) { - leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0 - } else { - var headIndex = getBidiPartAt(order, head.ch, head.sticky) - var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1) - if (headIndex == boundary - 1 || headIndex == boundary) - { leftSide = dir < 0 } - else - { leftSide = dir > 0 } - } - - var usePart = order[boundary + (leftSide ? -1 : 0)] - var from = leftSide == (usePart.level == 1) - var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before" - return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) - } - - - // Determines whether an event happened in the gutter, and fires the - // handlers for the corresponding event. - function gutterEvent(cm, e, type, prevent) { - var mX, mY - if (e.touches) { - mX = e.touches[0].clientX - mY = e.touches[0].clientY - } else { - try { mX = e.clientX; mY = e.clientY } - catch(e) { return false } - } - if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } - if (prevent) { e_preventDefault(e) } - - var display = cm.display - var lineBox = display.lineDiv.getBoundingClientRect() - - if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) } - mY -= lineBox.top - display.viewOffset - - for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i] - if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY) - var gutter = cm.options.gutters[i] - signal(cm, type, cm, line, gutter, e) - return e_defaultPrevented(e) - } - } - } - - function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true) - } - - // CONTEXT MENU HANDLING - - // To make the context menu work, we need to briefly unhide the - // textarea (making it as unobtrusive as possible) to let the - // right-click take effect on it. - function onContextMenu(cm, e) { - if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return } - if (signalDOMEvent(cm, e, "contextmenu")) { return } - cm.display.input.onContextMenu(e) - } - - function contextMenuInGutter(cm, e) { - if (!hasHandler(cm, "gutterContextMenu")) { return false } - return gutterEvent(cm, e, "gutterContextMenu", false) - } - - function themeChanged(cm) { - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-") - clearCaches(cm) - } - - var Init = {toString: function(){return "CodeMirror.Init"}} - - var defaults = {} - var optionHandlers = {} - - function defineOptions(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers - - function option(name, deflt, handle, notOnInit) { - CodeMirror.defaults[name] = deflt - if (handle) { optionHandlers[name] = - notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old) }} : handle } - } - - CodeMirror.defineOption = option - - // Passed to option handlers when there is no old value. - CodeMirror.Init = Init - - // These two are, on init, called from the constructor because they - // have to be initialized before the editor can start at all. - option("value", "", function (cm, val) { return cm.setValue(val); }, true) - option("mode", null, function (cm, val) { - cm.doc.modeOption = val - loadMode(cm) - }, true) - - option("indentUnit", 2, loadMode, true) - option("indentWithTabs", false) - option("smartIndent", true) - option("tabSize", 4, function (cm) { - resetModeState(cm) - clearCaches(cm) - regChange(cm) - }, true) - - option("lineSeparator", null, function (cm, val) { - cm.doc.lineSep = val - if (!val) { return } - var newBreaks = [], lineNo = cm.doc.first - cm.doc.iter(function (line) { - for (var pos = 0;;) { - var found = line.text.indexOf(val, pos) - if (found == -1) { break } - pos = found + val.length - newBreaks.push(Pos(lineNo, found)) - } - lineNo++ - }) - for (var i = newBreaks.length - 1; i >= 0; i--) - { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) } - }) - option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { - cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") - if (old != Init) { cm.refresh() } - }) - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true) - option("electricChars", true) - option("inputStyle", mobile ? "contenteditable" : "textarea", function () { - throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME - }, true) - option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true) - option("rtlMoveVisually", !windows) - option("wholeLineUpdateBefore", true) - - option("theme", "default", function (cm) { - themeChanged(cm) - guttersChanged(cm) - }, true) - option("keyMap", "default", function (cm, val, old) { - var next = getKeyMap(val) - var prev = old != Init && getKeyMap(old) - if (prev && prev.detach) { prev.detach(cm, next) } - if (next.attach) { next.attach(cm, prev || null) } - }) - option("extraKeys", null) - option("configureMouse", null) - - option("lineWrapping", false, wrappingChanged, true) - option("gutters", [], function (cm) { - setGuttersForLineNumbers(cm.options) - guttersChanged(cm) - }, true) - option("fixedGutter", true, function (cm, val) { - cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0" - cm.refresh() - }, true) - option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true) - option("scrollbarStyle", "native", function (cm) { - initScrollbars(cm) - updateScrollbars(cm) - cm.display.scrollbars.setScrollTop(cm.doc.scrollTop) - cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft) - }, true) - option("lineNumbers", false, function (cm) { - setGuttersForLineNumbers(cm.options) - guttersChanged(cm) - }, true) - option("firstLineNumber", 1, guttersChanged, true) - option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true) - option("showCursorWhenSelecting", false, updateSelection, true) - - option("resetSelectionOnContextMenu", true) - option("lineWiseCopyCut", true) - option("pasteLinesPerSelection", true) - - option("readOnly", false, function (cm, val) { - if (val == "nocursor") { - onBlur(cm) - cm.display.input.blur() - } - cm.display.input.readOnlyChanged(val) - }) - option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset() }}, true) - option("dragDrop", true, dragDropChanged) - option("allowDropFileTypes", null) - - option("cursorBlinkRate", 530) - option("cursorScrollMargin", 0) - option("cursorHeight", 1, updateSelection, true) - option("singleCursorHeightPerLine", true, updateSelection, true) - option("workTime", 100) - option("workDelay", 100) - option("flattenSpans", true, resetModeState, true) - option("addModeClass", false, resetModeState, true) - option("pollInterval", 100) - option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; }) - option("historyEventDelay", 1250) - option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true) - option("maxHighlightLength", 10000, resetModeState, true) - option("moveInputWithCursor", true, function (cm, val) { - if (!val) { cm.display.input.resetPosition() } - }) - - option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }) - option("autofocus", null) - option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true) - } - - function guttersChanged(cm) { - updateGutters(cm) - regChange(cm) - alignHorizontally(cm) - } - - function dragDropChanged(cm, value, old) { - var wasOn = old && old != Init - if (!value != !wasOn) { - var funcs = cm.display.dragFunctions - var toggle = value ? on : off - toggle(cm.display.scroller, "dragstart", funcs.start) - toggle(cm.display.scroller, "dragenter", funcs.enter) - toggle(cm.display.scroller, "dragover", funcs.over) - toggle(cm.display.scroller, "dragleave", funcs.leave) - toggle(cm.display.scroller, "drop", funcs.drop) - } - } - - function wrappingChanged(cm) { - if (cm.options.lineWrapping) { - addClass(cm.display.wrapper, "CodeMirror-wrap") - cm.display.sizer.style.minWidth = "" - cm.display.sizerWidth = null - } else { - rmClass(cm.display.wrapper, "CodeMirror-wrap") - findMaxLine(cm) - } - estimateLineHeights(cm) - regChange(cm) - clearCaches(cm) - setTimeout(function () { return updateScrollbars(cm); }, 100) - } - - // A CodeMirror instance represents an editor. This is the object - // that user code is usually dealing with. - - function CodeMirror(place, options) { - var this$1 = this; - - if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) } - - this.options = options = options ? copyObj(options) : {} - // Determine effective options based on given values and defaults. - copyObj(defaults, options, false) - setGuttersForLineNumbers(options) - - var doc = options.value - if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction) } - this.doc = doc - - var input = new CodeMirror.inputStyles[options.inputStyle](this) - var display = this.display = new Display(place, doc, input) - display.wrapper.CodeMirror = this - updateGutters(this) - themeChanged(this) - if (options.lineWrapping) - { this.display.wrapper.className += " CodeMirror-wrap" } - initScrollbars(this) - - this.state = { - keyMaps: [], // stores maps added by addKeyMap - overlays: [], // highlighting overlays, as added by addOverlay - modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info - overwrite: false, - delayingBlurEvent: false, - focused: false, - suppressEdits: false, // used to disable editing during key handlers when in readOnly mode - pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll - selectingText: false, - draggingText: false, - highlight: new Delayed(), // stores highlight worker timeout - keySeq: null, // Unfinished key sequence - specialChars: null - } - - if (options.autofocus && !mobile) { display.input.focus() } - - // Override magic textarea content restore that IE sometimes does - // on our hidden textarea on reload - if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) } - - registerEventHandlers(this) - ensureGlobalHandlers() - - startOperation(this) - this.curOp.forceUpdate = true - attachDoc(this, doc) - - if ((options.autofocus && !mobile) || this.hasFocus()) - { setTimeout(bind(onFocus, this), 20) } - else - { onBlur(this) } - - for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this$1, options[opt], Init) } } - maybeUpdateLineNumberWidth(this) - if (options.finishInit) { options.finishInit(this) } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1) } - endOperation(this) - // Suppress optimizelegibility in Webkit, since it breaks text - // measuring on line wrapping boundaries. - if (webkit && options.lineWrapping && - getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") - { display.lineDiv.style.textRendering = "auto" } - } - - // The default configuration options. - CodeMirror.defaults = defaults - // Functions to run when options are changed. - CodeMirror.optionHandlers = optionHandlers - - // Attach the necessary event handlers when initializing the editor - function registerEventHandlers(cm) { - var d = cm.display - on(d.scroller, "mousedown", operation(cm, onMouseDown)) - // Older IE's will not fire a second mousedown for a double click - if (ie && ie_version < 11) - { on(d.scroller, "dblclick", operation(cm, function (e) { - if (signalDOMEvent(cm, e)) { return } - var pos = posFromMouse(cm, e) - if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return } - e_preventDefault(e) - var word = cm.findWordAt(pos) - extendSelection(cm.doc, word.anchor, word.head) - })) } - else - { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }) } - // Some browsers fire contextmenu *after* opening the menu, at - // which point we can't mess with it anymore. Context menu is - // handled in onMouseDown for these browsers. - if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }) } - - // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = {end: 0} - function finishTouch() { - if (d.activeTouch) { - touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000) - prevTouch = d.activeTouch - prevTouch.end = +new Date - } - } - function isMouseLikeTouchEvent(e) { - if (e.touches.length != 1) { return false } - var touch = e.touches[0] - return touch.radiusX <= 1 && touch.radiusY <= 1 - } - function farAway(touch, other) { - if (other.left == null) { return true } - var dx = other.left - touch.left, dy = other.top - touch.top - return dx * dx + dy * dy > 20 * 20 - } - on(d.scroller, "touchstart", function (e) { - if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) { - d.input.ensurePolled() - clearTimeout(touchFinished) - var now = +new Date - d.activeTouch = {start: now, moved: false, - prev: now - prevTouch.end <= 300 ? prevTouch : null} - if (e.touches.length == 1) { - d.activeTouch.left = e.touches[0].pageX - d.activeTouch.top = e.touches[0].pageY - } - } - }) - on(d.scroller, "touchmove", function () { - if (d.activeTouch) { d.activeTouch.moved = true } - }) - on(d.scroller, "touchend", function (e) { - var touch = d.activeTouch - if (touch && !eventInWidget(d, e) && touch.left != null && - !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range - if (!touch.prev || farAway(touch, touch.prev)) // Single tap - { range = new Range(pos, pos) } - else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap - { range = cm.findWordAt(pos) } - else // Triple tap - { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } - cm.setSelection(range.anchor, range.head) - cm.focus() - e_preventDefault(e) - } - finishTouch() - }) - on(d.scroller, "touchcancel", finishTouch) - - // Sync scrolling between fake scrollbars and real scrollable - // area, ensure viewport is updated when scrolling. - on(d.scroller, "scroll", function () { - if (d.scroller.clientHeight) { - updateScrollTop(cm, d.scroller.scrollTop) - setScrollLeft(cm, d.scroller.scrollLeft, true) - signal(cm, "scroll", cm) - } - }) - - // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); }) - on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); }) - - // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }) - - d.dragFunctions = { - enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e) }}, - over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, - start: function (e) { return onDragStart(cm, e); }, - drop: operation(cm, onDrop), - leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} - } - - var inp = d.input.getField() - on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); }) - on(inp, "keydown", operation(cm, onKeyDown)) - on(inp, "keypress", operation(cm, onKeyPress)) - on(inp, "focus", function (e) { return onFocus(cm, e); }) - on(inp, "blur", function (e) { return onBlur(cm, e); }) - } - - var initHooks = [] - CodeMirror.defineInitHook = function (f) { return initHooks.push(f); } - - // Indent the given line. The how parameter can be "smart", - // "add"/null, "subtract", or "prev". When aggressive is false - // (typically set to true for forced single-line indents), empty - // lines are not indented, and places where the mode returns Pass - // are left alone. - function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state - if (how == null) { how = "add" } - if (how == "smart") { - // Fall back to "prev" when the mode doesn't have an indentation - // method. - if (!doc.mode.indent) { how = "prev" } - else { state = getContextBefore(cm, n).state } - } - - var tabSize = cm.options.tabSize - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) - if (line.stateAfter) { line.stateAfter = null } - var curSpaceString = line.text.match(/^\s*/)[0], indentation - if (!aggressive && !/\S/.test(line.text)) { - indentation = 0 - how = "not" - } else if (how == "smart") { - indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) - if (indentation == Pass || indentation > 150) { - if (!aggressive) { return } - how = "prev" - } - } - if (how == "prev") { - if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize) } - else { indentation = 0 } - } else if (how == "add") { - indentation = curSpace + cm.options.indentUnit - } else if (how == "subtract") { - indentation = curSpace - cm.options.indentUnit - } else if (typeof how == "number") { - indentation = curSpace + how - } - indentation = Math.max(0, indentation) - - var indentString = "", pos = 0 - if (cm.options.indentWithTabs) - { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} } - if (pos < indentation) { indentString += spaceStr(indentation - pos) } - - if (indentString != curSpaceString) { - replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") - line.stateAfter = null - return true - } else { - // Ensure that, if the cursor was in the whitespace at the start - // of the line, it is moved to the end of that space. - for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) { - var range = doc.sel.ranges[i$1] - if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos$1 = Pos(n, curSpaceString.length) - replaceOneSelection(doc, i$1, new Range(pos$1, pos$1)) - break - } - } - } - } - - // This will be set to a {lineWise: bool, text: [string]} object, so - // that, when pasting, we know what kind of selections the copied - // text was made out of. - var lastCopied = null - - function setLastCopied(newLastCopied) { - lastCopied = newLastCopied - } - - function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc - cm.display.shift = false - if (!sel) { sel = doc.sel } - - var paste = cm.state.pasteIncoming || origin == "paste" - var textLines = splitLinesAuto(inserted), multiPaste = null - // When pasting N lines into N selections, insert one line per selection - if (paste && sel.ranges.length > 1) { - if (lastCopied && lastCopied.text.join("\n") == inserted) { - if (sel.ranges.length % lastCopied.text.length == 0) { - multiPaste = [] - for (var i = 0; i < lastCopied.text.length; i++) - { multiPaste.push(doc.splitLines(lastCopied.text[i])) } - } - } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) { - multiPaste = map(textLines, function (l) { return [l]; }) - } - } - - var updateInput - // Normal behavior is to insert the new text into every selection - for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { - var range = sel.ranges[i$1] - var from = range.from(), to = range.to() - if (range.empty()) { - if (deleted && deleted > 0) // Handle deletion - { from = Pos(from.line, from.ch - deleted) } - else if (cm.state.overwrite && !paste) // Handle overwrite - { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)) } - else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) - { from = to = Pos(from.line, 0) } - } - updateInput = cm.curOp.updateInput - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} - makeChange(cm.doc, changeEvent) - signalLater(cm, "inputRead", cm, changeEvent) - } - if (inserted && !paste) - { triggerElectric(cm, inserted) } - - ensureCursorVisible(cm) - cm.curOp.updateInput = updateInput - cm.curOp.typing = true - cm.state.pasteIncoming = cm.state.cutIncoming = false - } - - function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("Text") - if (pasted) { - e.preventDefault() - if (!cm.isReadOnly() && !cm.options.disableInput) - { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }) } - return true - } - } - - function triggerElectric(cm, inserted) { - // When an 'electric' character is inserted, immediately trigger a reindent - if (!cm.options.electricChars || !cm.options.smartIndent) { return } - var sel = cm.doc.sel - - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i] - if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } - var mode = cm.getModeAt(range.head) - var indented = false - if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) - { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range.head.line, "smart") - break - } } - } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) - { indented = indentLine(cm, range.head.line, "smart") } - } - if (indented) { signalLater(cm, "electricInput", cm, range.head.line) } - } - } - - function copyableRanges(cm) { - var text = [], ranges = [] - for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line - var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} - ranges.push(lineRange) - text.push(cm.getRange(lineRange.anchor, lineRange.head)) - } - return {text: text, ranges: ranges} - } - - function disableBrowserMagic(field, spellcheck) { - field.setAttribute("autocorrect", "off") - field.setAttribute("autocapitalize", "off") - field.setAttribute("spellcheck", !!spellcheck) - } - - function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") - // The textarea is kept positioned near the cursor to prevent the - // fact that it'll be scrolled into view on input from scrolling - // our fake cursor out of view. On webkit, when wrap=off, paste is - // very slow. So make the area wide instead. - if (webkit) { te.style.width = "1000px" } - else { te.setAttribute("wrap", "off") } - // If border: 0; -- iOS fails to open keyboard (issue #1287) - if (ios) { te.style.border = "1px solid black" } - disableBrowserMagic(te) - return div - } - - // The publicly visible API. Note that methodOp(f) means - // 'wrap f in an operation, performed on its `this` parameter'. - - // This is not the complete set of editor methods. Most of the - // methods defined on the Doc type are also injected into - // CodeMirror.prototype, for backwards compatibility and - // convenience. - - function addEditorMethods(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers - - var helpers = CodeMirror.helpers = {} - - CodeMirror.prototype = { - constructor: CodeMirror, - focus: function(){window.focus(); this.display.input.focus()}, - - setOption: function(option, value) { - var options = this.options, old = options[option] - if (options[option] == value && option != "mode") { return } - options[option] = value - if (optionHandlers.hasOwnProperty(option)) - { operation(this, optionHandlers[option])(this, value, old) } - signal(this, "optionChange", this, option) - }, - - getOption: function(option) {return this.options[option]}, - getDoc: function() {return this.doc}, - - addKeyMap: function(map, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)) - }, - removeKeyMap: function(map) { - var maps = this.state.keyMaps - for (var i = 0; i < maps.length; ++i) - { if (maps[i] == map || maps[i].name == map) { - maps.splice(i, 1) - return true - } } - }, - - addOverlay: methodOp(function(spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) - if (mode.startState) { throw new Error("Overlays may not be stateful.") } - insertSorted(this.state.overlays, - {mode: mode, modeSpec: spec, opaque: options && options.opaque, - priority: (options && options.priority) || 0}, - function (overlay) { return overlay.priority; }) - this.state.modeGen++ - regChange(this) - }), - removeOverlay: methodOp(function(spec) { - var this$1 = this; - - var overlays = this.state.overlays - for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec - if (cur == spec || typeof spec == "string" && cur.name == spec) { - overlays.splice(i, 1) - this$1.state.modeGen++ - regChange(this$1) - return - } - } - }), - - indentLine: methodOp(function(n, dir, aggressive) { - if (typeof dir != "string" && typeof dir != "number") { - if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev" } - else { dir = dir ? "add" : "subtract" } - } - if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive) } - }), - indentSelection: methodOp(function(how) { - var this$1 = this; - - var ranges = this.doc.sel.ranges, end = -1 - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i] - if (!range.empty()) { - var from = range.from(), to = range.to() - var start = Math.max(end, from.line) - end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 - for (var j = start; j < end; ++j) - { indentLine(this$1, j, how) } - var newRanges = this$1.doc.sel.ranges - if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } - } else if (range.head.line > end) { - indentLine(this$1, range.head.line, how, true) - end = range.head.line - if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1) } - } - } - }), - - // Fetch the parser token for a given character. Useful for hacks - // that want to inspect the mode state (say, for completion). - getTokenAt: function(pos, precise) { - return takeToken(this, pos, precise) - }, - - getLineTokens: function(line, precise) { - return takeToken(this, Pos(line), precise, true) - }, - - getTokenTypeAt: function(pos) { - pos = clipPos(this.doc, pos) - var styles = getLineStyles(this, getLine(this.doc, pos.line)) - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch - var type - if (ch == 0) { type = styles[2] } - else { for (;;) { - var mid = (before + after) >> 1 - if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid } - else if (styles[mid * 2 + 1] < ch) { before = mid + 1 } - else { type = styles[mid * 2 + 2]; break } - } } - var cut = type ? type.indexOf("overlay ") : -1 - return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) - }, - - getModeAt: function(pos) { - var mode = this.doc.mode - if (!mode.innerMode) { return mode } - return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode - }, - - getHelper: function(pos, type) { - return this.getHelpers(pos, type)[0] - }, - - getHelpers: function(pos, type) { - var this$1 = this; - - var found = [] - if (!helpers.hasOwnProperty(type)) { return found } - var help = helpers[type], mode = this.getModeAt(pos) - if (typeof mode[type] == "string") { - if (help[mode[type]]) { found.push(help[mode[type]]) } - } else if (mode[type]) { - for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]] - if (val) { found.push(val) } - } - } else if (mode.helperType && help[mode.helperType]) { - found.push(help[mode.helperType]) - } else if (help[mode.name]) { - found.push(help[mode.name]) - } - for (var i$1 = 0; i$1 < help._global.length; i$1++) { - var cur = help._global[i$1] - if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) - { found.push(cur.val) } - } - return found - }, - - getStateAfter: function(line, precise) { - var doc = this.doc - line = clipLine(doc, line == null ? doc.first + doc.size - 1: line) - return getContextBefore(this, line + 1, precise).state - }, - - cursorCoords: function(start, mode) { - var pos, range = this.doc.sel.primary() - if (start == null) { pos = range.head } - else if (typeof start == "object") { pos = clipPos(this.doc, start) } - else { pos = start ? range.from() : range.to() } - return cursorCoords(this, pos, mode || "page") - }, - - charCoords: function(pos, mode) { - return charCoords(this, clipPos(this.doc, pos), mode || "page") - }, - - coordsChar: function(coords, mode) { - coords = fromCoordSystem(this, coords, mode || "page") - return coordsChar(this, coords.left, coords.top) - }, - - lineAtHeight: function(height, mode) { - height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top - return lineAtHeight(this.doc, height + this.display.viewOffset) - }, - heightAtLine: function(line, mode, includeWidgets) { - var end = false, lineObj - if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1 - if (line < this.doc.first) { line = this.doc.first } - else if (line > last) { line = last; end = true } - lineObj = getLine(this.doc, line) - } else { - lineObj = line - } - return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top + - (end ? this.doc.height - heightAtLine(lineObj) : 0) - }, - - defaultTextHeight: function() { return textHeight(this.display) }, - defaultCharWidth: function() { return charWidth(this.display) }, - - getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, - - addWidget: function(pos, node, scroll, vert, horiz) { - var display = this.display - pos = cursorCoords(this, clipPos(this.doc, pos)) - var top = pos.bottom, left = pos.left - node.style.position = "absolute" - node.setAttribute("cm-ignore-events", "true") - this.display.input.setUneditable(node) - display.sizer.appendChild(node) - if (vert == "over") { - top = pos.top - } else if (vert == "above" || vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth) - // Default to positioning above (if specified and possible); otherwise default to positioning below - if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) - { top = pos.top - node.offsetHeight } - else if (pos.bottom + node.offsetHeight <= vspace) - { top = pos.bottom } - if (left + node.offsetWidth > hspace) - { left = hspace - node.offsetWidth } - } - node.style.top = top + "px" - node.style.left = node.style.right = "" - if (horiz == "right") { - left = display.sizer.clientWidth - node.offsetWidth - node.style.right = "0px" - } else { - if (horiz == "left") { left = 0 } - else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2 } - node.style.left = left + "px" - } - if (scroll) - { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}) } - }, - - triggerOnKeyDown: methodOp(onKeyDown), - triggerOnKeyPress: methodOp(onKeyPress), - triggerOnKeyUp: onKeyUp, - triggerOnMouseDown: methodOp(onMouseDown), - - execCommand: function(cmd) { - if (commands.hasOwnProperty(cmd)) - { return commands[cmd].call(null, this) } - }, - - triggerElectric: methodOp(function(text) { triggerElectric(this, text) }), - - findPosH: function(from, amount, unit, visually) { - var this$1 = this; - - var dir = 1 - if (amount < 0) { dir = -1; amount = -amount } - var cur = clipPos(this.doc, from) - for (var i = 0; i < amount; ++i) { - cur = findPosH(this$1.doc, cur, dir, unit, visually) - if (cur.hitSide) { break } - } - return cur - }, - - moveH: methodOp(function(dir, unit) { - var this$1 = this; - - this.extendSelectionsBy(function (range) { - if (this$1.display.shift || this$1.doc.extend || range.empty()) - { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } - else - { return dir < 0 ? range.from() : range.to() } - }, sel_move) - }), - - deleteH: methodOp(function(dir, unit) { - var sel = this.doc.sel, doc = this.doc - if (sel.somethingSelected()) - { doc.replaceSelection("", null, "+delete") } - else - { deleteNearSelection(this, function (range) { - var other = findPosH(doc, range.head, dir, unit, false) - return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} - }) } - }), - - findPosV: function(from, amount, unit, goalColumn) { - var this$1 = this; - - var dir = 1, x = goalColumn - if (amount < 0) { dir = -1; amount = -amount } - var cur = clipPos(this.doc, from) - for (var i = 0; i < amount; ++i) { - var coords = cursorCoords(this$1, cur, "div") - if (x == null) { x = coords.left } - else { coords.left = x } - cur = findPosV(this$1, coords, dir, unit) - if (cur.hitSide) { break } - } - return cur - }, - - moveV: methodOp(function(dir, unit) { - var this$1 = this; - - var doc = this.doc, goals = [] - var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected() - doc.extendSelectionsBy(function (range) { - if (collapse) - { return dir < 0 ? range.from() : range.to() } - var headPos = cursorCoords(this$1, range.head, "div") - if (range.goalColumn != null) { headPos.left = range.goalColumn } - goals.push(headPos.left) - var pos = findPosV(this$1, headPos, dir, unit) - if (unit == "page" && range == doc.sel.primary()) - { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top) } - return pos - }, sel_move) - if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++) - { doc.sel.ranges[i].goalColumn = goals[i] } } - }), - - // Find the word at the given position (as returned by coordsChar). - findWordAt: function(pos) { - var doc = this.doc, line = getLine(doc, pos.line).text - var start = pos.ch, end = pos.ch - if (line) { - var helper = this.getHelper(pos, "wordChars") - if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end } - var startChar = line.charAt(start) - var check = isWordChar(startChar, helper) - ? function (ch) { return isWordChar(ch, helper); } - : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } - : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); } - while (start > 0 && check(line.charAt(start - 1))) { --start } - while (end < line.length && check(line.charAt(end))) { ++end } - } - return new Range(Pos(pos.line, start), Pos(pos.line, end)) - }, - - toggleOverwrite: function(value) { - if (value != null && value == this.state.overwrite) { return } - if (this.state.overwrite = !this.state.overwrite) - { addClass(this.display.cursorDiv, "CodeMirror-overwrite") } - else - { rmClass(this.display.cursorDiv, "CodeMirror-overwrite") } - - signal(this, "overwriteToggle", this, this.state.overwrite) - }, - hasFocus: function() { return this.display.input.getField() == activeElt() }, - isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, - - scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y) }), - getScrollInfo: function() { - var scroller = this.display.scroller - return {left: scroller.scrollLeft, top: scroller.scrollTop, - height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, - width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, - clientHeight: displayHeight(this), clientWidth: displayWidth(this)} - }, - - scrollIntoView: methodOp(function(range, margin) { - if (range == null) { - range = {from: this.doc.sel.primary().head, to: null} - if (margin == null) { margin = this.options.cursorScrollMargin } - } else if (typeof range == "number") { - range = {from: Pos(range, 0), to: null} - } else if (range.from == null) { - range = {from: range, to: null} - } - if (!range.to) { range.to = range.from } - range.margin = margin || 0 - - if (range.from.line != null) { - scrollToRange(this, range) - } else { - scrollToCoordsRange(this, range.from, range.to, range.margin) - } - }), - - setSize: methodOp(function(width, height) { - var this$1 = this; - - var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } - if (width != null) { this.display.wrapper.style.width = interpret(width) } - if (height != null) { this.display.wrapper.style.height = interpret(height) } - if (this.options.lineWrapping) { clearLineMeasurementCache(this) } - var lineNo = this.display.viewFrom - this.doc.iter(lineNo, this.display.viewTo, function (line) { - if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) - { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } - ++lineNo - }) - this.curOp.forceUpdate = true - signal(this, "refresh", this) - }), - - operation: function(f){return runInOp(this, f)}, - startOperation: function(){return startOperation(this)}, - endOperation: function(){return endOperation(this)}, - - refresh: methodOp(function() { - var oldHeight = this.display.cachedTextHeight - regChange(this) - this.curOp.forceUpdate = true - clearCaches(this) - scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop) - updateGutterSpace(this) - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) - { estimateLineHeights(this) } - signal(this, "refresh", this) - }), - - swapDoc: methodOp(function(doc) { - var old = this.doc - old.cm = null - attachDoc(this, doc) - clearCaches(this) - this.display.input.reset() - scrollToCoords(this, doc.scrollLeft, doc.scrollTop) - this.curOp.forceScroll = true - signalLater(this, "swapDoc", this, old) - return old - }), - - getInputField: function(){return this.display.input.getField()}, - getWrapperElement: function(){return this.display.wrapper}, - getScrollerElement: function(){return this.display.scroller}, - getGutterElement: function(){return this.display.gutters} - } - eventMixin(CodeMirror) - - CodeMirror.registerHelper = function(type, name, value) { - if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []} } - helpers[type][name] = value - } - CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { - CodeMirror.registerHelper(type, name, value) - helpers[type]._global.push({pred: predicate, val: value}) - } - } - - // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosH(doc, pos, dir, unit, visually) { - var oldPos = pos - var origDir = dir - var lineObj = getLine(doc, pos.line) - function findNextLine() { - var l = pos.line + dir - if (l < doc.first || l >= doc.first + doc.size) { return false } - pos = new Pos(l, pos.ch, pos.sticky) - return lineObj = getLine(doc, l) - } - function moveOnce(boundToLine) { - var next - if (visually) { - next = moveVisually(doc.cm, lineObj, pos, dir) - } else { - next = moveLogically(lineObj, pos, dir) - } - if (next == null) { - if (!boundToLine && findNextLine()) - { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir) } - else - { return false } - } else { - pos = next - } - return true - } - - if (unit == "char") { - moveOnce() - } else if (unit == "column") { - moveOnce(true) - } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group" - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars") - for (var first = true;; first = false) { - if (dir < 0 && !moveOnce(!first)) { break } - var cur = lineObj.text.charAt(pos.ch) || "\n" - var type = isWordChar(cur, helper) ? "w" - : group && cur == "\n" ? "n" - : !group || /\s/.test(cur) ? null - : "p" - if (group && !first && !type) { type = "s" } - if (sawType && sawType != type) { - if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after"} - break - } - - if (type) { sawType = type } - if (dir > 0 && !moveOnce(!first)) { break } - } - } - var result = skipAtomic(doc, pos, oldPos, origDir, true) - if (equalCursorPos(oldPos, result)) { result.hitSide = true } - return result - } - - // For relative vertical movement. Dir may be -1 or 1. Unit can be - // "page" or "line". The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y - if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) - var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) - y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount - - } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3 - } - var target - for (;;) { - target = coordsChar(cm, x, y) - if (!target.outside) { break } - if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } - y += dir * 5 - } - return target - } - - // CONTENTEDITABLE INPUT STYLE - - var ContentEditableInput = function(cm) { - this.cm = cm - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null - this.polling = new Delayed() - this.composing = null - this.gracePeriod = false - this.readDOMTimeout = null - }; - - ContentEditableInput.prototype.init = function (display) { - var this$1 = this; - - var input = this, cm = input.cm - var div = input.div = display.lineDiv - disableBrowserMagic(div, cm.options.spellcheck) - - on(div, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } - // IE doesn't fire input events, so we schedule a read for the pasted content in this way - if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20) } - }) - - on(div, "compositionstart", function (e) { - this$1.composing = {data: e.data, done: false} - }) - on(div, "compositionupdate", function (e) { - if (!this$1.composing) { this$1.composing = {data: e.data, done: false} } - }) - on(div, "compositionend", function (e) { - if (this$1.composing) { - if (e.data != this$1.composing.data) { this$1.readFromDOMSoon() } - this$1.composing.done = true - } - }) - - on(div, "touchstart", function () { return input.forceCompositionEnd(); }) - - on(div, "input", function () { - if (!this$1.composing) { this$1.readFromDOMSoon() } - }) - - function onCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } - if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}) - if (e.type == "cut") { cm.replaceSelection("", null, "cut") } - } else if (!cm.options.lineWiseCopyCut) { - return - } else { - var ranges = copyableRanges(cm) - setLastCopied({lineWise: true, text: ranges.text}) - if (e.type == "cut") { - cm.operation(function () { - cm.setSelections(ranges.ranges, 0, sel_dontScroll) - cm.replaceSelection("", null, "cut") - }) - } - } - if (e.clipboardData) { - e.clipboardData.clearData() - var content = lastCopied.text.join("\n") - // iOS exposes the clipboard API, but seems to discard content inserted into it - e.clipboardData.setData("Text", content) - if (e.clipboardData.getData("Text") == content) { - e.preventDefault() - return - } - } - // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild - cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) - te.value = lastCopied.text.join("\n") - var hadFocus = document.activeElement - selectInput(te) - setTimeout(function () { - cm.display.lineSpace.removeChild(kludge) - hadFocus.focus() - if (hadFocus == div) { input.showPrimarySelection() } - }, 50) - } - on(div, "copy", onCopyCut) - on(div, "cut", onCopyCut) - }; - - ContentEditableInput.prototype.prepareSelection = function () { - var result = prepareSelection(this.cm, false) - result.focus = this.cm.state.focused - return result - }; - - ContentEditableInput.prototype.showSelection = function (info, takeFocus) { - if (!info || !this.cm.display.view.length) { return } - if (info.focus || takeFocus) { this.showPrimarySelection() } - this.showMultipleSelections(info) - }; - - ContentEditableInput.prototype.showPrimarySelection = function () { - var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() - var from = prim.from(), to = prim.to() - - if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { - sel.removeAllRanges() - return - } - - var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) - var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset) - if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && - cmp(minPos(curAnchor, curFocus), from) == 0 && - cmp(maxPos(curAnchor, curFocus), to) == 0) - { return } - - var view = cm.display.view - var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) || - {node: view[0].measure.map[2], offset: 0} - var end = to.line < cm.display.viewTo && posToDOM(cm, to) - if (!end) { - var measure = view[view.length - 1].measure - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map - end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]} - } - - if (!start || !end) { - sel.removeAllRanges() - return - } - - var old = sel.rangeCount && sel.getRangeAt(0), rng - try { rng = range(start.node, start.offset, end.offset, end.node) } - catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible - if (rng) { - if (!gecko && cm.state.focused) { - sel.collapse(start.node, start.offset) - if (!rng.collapsed) { - sel.removeAllRanges() - sel.addRange(rng) - } - } else { - sel.removeAllRanges() - sel.addRange(rng) - } - if (old && sel.anchorNode == null) { sel.addRange(old) } - else if (gecko) { this.startGracePeriod() } - } - this.rememberSelection() - }; - - ContentEditableInput.prototype.startGracePeriod = function () { - var this$1 = this; - - clearTimeout(this.gracePeriod) - this.gracePeriod = setTimeout(function () { - this$1.gracePeriod = false - if (this$1.selectionChanged()) - { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) } - }, 20) - }; - - ContentEditableInput.prototype.showMultipleSelections = function (info) { - removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors) - removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection) - }; - - ContentEditableInput.prototype.rememberSelection = function () { - var sel = window.getSelection() - this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset - this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset - }; - - ContentEditableInput.prototype.selectionInEditor = function () { - var sel = window.getSelection() - if (!sel.rangeCount) { return false } - var node = sel.getRangeAt(0).commonAncestorContainer - return contains(this.div, node) - }; - - ContentEditableInput.prototype.focus = function () { - if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor()) - { this.showSelection(this.prepareSelection(), true) } - this.div.focus() - } - }; - ContentEditableInput.prototype.blur = function () { this.div.blur() }; - ContentEditableInput.prototype.getField = function () { return this.div }; - - ContentEditableInput.prototype.supportsTouch = function () { return true }; - - ContentEditableInput.prototype.receivedFocus = function () { - var input = this - if (this.selectionInEditor()) - { this.pollSelection() } - else - { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) } - - function poll() { - if (input.cm.state.focused) { - input.pollSelection() - input.polling.set(input.cm.options.pollInterval, poll) - } - } - this.polling.set(this.cm.options.pollInterval, poll) - }; - - ContentEditableInput.prototype.selectionChanged = function () { - var sel = window.getSelection() - return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset - }; - - ContentEditableInput.prototype.pollSelection = function () { - if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } - var sel = window.getSelection(), cm = this.cm - // On Android Chrome (version 56, at least), backspacing into an - // uneditable block element will put the cursor in that element, - // and then, because it's not editable, hide the virtual keyboard. - // Because Android doesn't allow us to actually detect backspace - // presses in a sane way, this code checks for when that happens - // and simulates a backspace press in this case. - if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) { - this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs}) - this.blur() - this.focus() - return - } - if (this.composing) { return } - this.rememberSelection() - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) - var head = domToPos(cm, sel.focusNode, sel.focusOffset) - if (anchor && head) { runInOp(cm, function () { - setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) - if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true } - }) } - }; - - ContentEditableInput.prototype.pollContent = function () { - if (this.readDOMTimeout != null) { - clearTimeout(this.readDOMTimeout) - this.readDOMTimeout = null - } - - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() - var from = sel.from(), to = sel.to() - if (from.ch == 0 && from.line > cm.firstLine()) - { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) } - if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) - { to = Pos(to.line + 1, 0) } - if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false } - - var fromIndex, fromLine, fromNode - if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - fromLine = lineNo(display.view[0].line) - fromNode = display.view[0].node - } else { - fromLine = lineNo(display.view[fromIndex].line) - fromNode = display.view[fromIndex - 1].node.nextSibling - } - var toIndex = findViewIndex(cm, to.line) - var toLine, toNode - if (toIndex == display.view.length - 1) { - toLine = display.viewTo - 1 - toNode = display.lineDiv.lastChild - } else { - toLine = lineNo(display.view[toIndex + 1].line) - 1 - toNode = display.view[toIndex + 1].node.previousSibling - } - - if (!fromNode) { return false } - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) - while (newText.length > 1 && oldText.length > 1) { - if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- } - else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ } - else { break } - } - - var cutFront = 0, cutEnd = 0 - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) - while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) - { ++cutFront } - var newBot = lst(newText), oldBot = lst(oldText) - var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), - oldBot.length - (oldText.length == 1 ? cutFront : 0)) - while (cutEnd < maxCutEnd && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) - { ++cutEnd } - // Try to move start of change to start of selection if ambiguous - if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) { - while (cutFront && cutFront > from.ch && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) { - cutFront-- - cutEnd++ - } - } - - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "") - newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "") - - var chFrom = Pos(fromLine, cutFront) - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) - if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { - replaceRange(cm.doc, newText, chFrom, chTo, "+input") - return true - } - }; - - ContentEditableInput.prototype.ensurePolled = function () { - this.forceCompositionEnd() - }; - ContentEditableInput.prototype.reset = function () { - this.forceCompositionEnd() - }; - ContentEditableInput.prototype.forceCompositionEnd = function () { - if (!this.composing) { return } - clearTimeout(this.readDOMTimeout) - this.composing = null - this.updateFromDOM() - this.div.blur() - this.div.focus() - }; - ContentEditableInput.prototype.readFromDOMSoon = function () { - var this$1 = this; - - if (this.readDOMTimeout != null) { return } - this.readDOMTimeout = setTimeout(function () { - this$1.readDOMTimeout = null - if (this$1.composing) { - if (this$1.composing.done) { this$1.composing = null } - else { return } - } - this$1.updateFromDOM() - }, 80) - }; - - ContentEditableInput.prototype.updateFromDOM = function () { - var this$1 = this; - - if (this.cm.isReadOnly() || !this.pollContent()) - { runInOp(this.cm, function () { return regChange(this$1.cm); }) } - }; - - ContentEditableInput.prototype.setUneditable = function (node) { - node.contentEditable = "false" - }; - - ContentEditableInput.prototype.onKeyPress = function (e) { - if (e.charCode == 0 || this.composing) { return } - e.preventDefault() - if (!this.cm.isReadOnly()) - { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) } - }; - - ContentEditableInput.prototype.readOnlyChanged = function (val) { - this.div.contentEditable = String(val != "nocursor") - }; - - ContentEditableInput.prototype.onContextMenu = function () {}; - ContentEditableInput.prototype.resetPosition = function () {}; - - ContentEditableInput.prototype.needsContentAttribute = true - - function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line) - if (!view || view.hidden) { return null } - var line = getLine(cm.doc, pos.line) - var info = mapFromLineView(view, line, pos.line) - - var order = getOrder(line, cm.doc.direction), side = "left" - if (order) { - var partPos = getBidiPartAt(order, pos.ch) - side = partPos % 2 ? "right" : "left" - } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side) - result.offset = result.collapse == "right" ? result.end : result.start - return result - } - - function isInGutter(node) { - for (var scan = node; scan; scan = scan.parentNode) - { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } } - return false - } - - function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } - - function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator() - function recognizeMarker(id) { return function (marker) { return marker.id == id; } } - function close() { - if (closing) { - text += lineSep - closing = false - } - } - function addText(str) { - if (str) { - close() - text += str - } - } - function walk(node) { - if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text") - if (cmText != null) { - addText(cmText || node.textContent.replace(/\u200b/g, "")) - return - } - var markerID = node.getAttribute("cm-marker"), range - if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) - if (found.length && (range = found[0].find(0))) - { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)) } - return - } - if (node.getAttribute("contenteditable") == "false") { return } - var isBlock = /^(pre|div|p)$/i.test(node.nodeName) - if (isBlock) { close() } - for (var i = 0; i < node.childNodes.length; i++) - { walk(node.childNodes[i]) } - if (isBlock) { closing = true } - } else if (node.nodeType == 3) { - addText(node.nodeValue) - } - } - for (;;) { - walk(from) - if (from == to) { break } - from = from.nextSibling - } - return text - } - - function domToPos(cm, node, offset) { - var lineNode - if (node == cm.display.lineDiv) { - lineNode = cm.display.lineDiv.childNodes[offset] - if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) } - node = null; offset = 0 - } else { - for (lineNode = node;; lineNode = lineNode.parentNode) { - if (!lineNode || lineNode == cm.display.lineDiv) { return null } - if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break } - } - } - for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i] - if (lineView.node == lineNode) - { return locateNodeInLineView(lineView, node, offset) } - } - } - - function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false - if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) } - if (node == wrapper) { - bad = true - node = wrapper.childNodes[offset] - offset = 0 - if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line - return badPos(Pos(lineNo(line), line.text.length), bad) - } - } - - var textNode = node.nodeType == 3 ? node : null, topNode = node - if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { - textNode = node.firstChild - if (offset) { offset = textNode.nodeValue.length } - } - while (topNode.parentNode != wrapper) { topNode = topNode.parentNode } - var measure = lineView.measure, maps = measure.maps - - function find(textNode, topNode, offset) { - for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i] - for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2] - if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) - var ch = map[j] + offset - if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)] } - return Pos(line, ch) - } - } - } - } - var found = find(textNode, topNode, offset) - if (found) { return badPos(found, bad) } - - // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems - for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { - found = find(after, after.firstChild, 0) - if (found) - { return badPos(Pos(found.line, found.ch - dist), bad) } - else - { dist += after.textContent.length } - } - for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) { - found = find(before, before.firstChild, -1) - if (found) - { return badPos(Pos(found.line, found.ch + dist$1), bad) } - else - { dist$1 += before.textContent.length } - } - } - - // TEXTAREA INPUT STYLE - - var TextareaInput = function(cm) { - this.cm = cm - // See input.poll and input.reset - this.prevInput = "" - - // Flag that indicates whether we expect input to appear real soon - // now (after some event like 'keypress' or 'input') and are - // polling intensively. - this.pollingFast = false - // Self-resetting timeout for the poller - this.polling = new Delayed() - // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false - this.composing = null - }; - - TextareaInput.prototype.init = function (display) { - var this$1 = this; - - var input = this, cm = this.cm - this.createField(display) - var te = this.textarea - - display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild) - - // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) - if (ios) { te.style.width = "0px" } - - on(te, "input", function () { - if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null } - input.poll() - }) - - on(te, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } - - cm.state.pasteIncoming = true - input.fastPoll() - }) - - function prepareCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } - if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}) - } else if (!cm.options.lineWiseCopyCut) { - return - } else { - var ranges = copyableRanges(cm) - setLastCopied({lineWise: true, text: ranges.text}) - if (e.type == "cut") { - cm.setSelections(ranges.ranges, null, sel_dontScroll) - } else { - input.prevInput = "" - te.value = ranges.text.join("\n") - selectInput(te) - } - } - if (e.type == "cut") { cm.state.cutIncoming = true } - } - on(te, "cut", prepareCopyCut) - on(te, "copy", prepareCopyCut) - - on(display.scroller, "paste", function (e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } - cm.state.pasteIncoming = true - input.focus() - }) - - // Prevent normal selection in the editor (we handle our own) - on(display.lineSpace, "selectstart", function (e) { - if (!eventInWidget(display, e)) { e_preventDefault(e) } - }) - - on(te, "compositionstart", function () { - var start = cm.getCursor("from") - if (input.composing) { input.composing.range.clear() } - input.composing = { - start: start, - range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) - } - }) - on(te, "compositionend", function () { - if (input.composing) { - input.poll() - input.composing.range.clear() - input.composing = null - } - }) - }; - - TextareaInput.prototype.createField = function (_display) { - // Wraps and hides input textarea - this.wrapper = hiddenTextarea() - // The semihidden textarea that is focused when the editor is - // focused, and receives input. - this.textarea = this.wrapper.firstChild - }; - - TextareaInput.prototype.prepareSelection = function () { - // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc - var result = prepareSelection(cm) - - // Move the hidden textarea near the cursor to prevent scrolling artifacts - if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div") - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() - result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)) - result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)) - } - - return result - }; - - TextareaInput.prototype.showSelection = function (drawn) { - var cm = this.cm, display = cm.display - removeChildrenAndAdd(display.cursorDiv, drawn.cursors) - removeChildrenAndAdd(display.selectionDiv, drawn.selection) - if (drawn.teTop != null) { - this.wrapper.style.top = drawn.teTop + "px" - this.wrapper.style.left = drawn.teLeft + "px" - } - }; - - // Reset the input to correspond to the selection (or to be empty, - // when not typing and nothing is selected) - TextareaInput.prototype.reset = function (typing) { - if (this.contextMenuPending || this.composing) { return } - var cm = this.cm - if (cm.somethingSelected()) { - this.prevInput = "" - var content = cm.getSelection() - this.textarea.value = content - if (cm.state.focused) { selectInput(this.textarea) } - if (ie && ie_version >= 9) { this.hasSelection = content } - } else if (!typing) { - this.prevInput = this.textarea.value = "" - if (ie && ie_version >= 9) { this.hasSelection = null } - } - }; - - TextareaInput.prototype.getField = function () { return this.textarea }; - - TextareaInput.prototype.supportsTouch = function () { return false }; - - TextareaInput.prototype.focus = function () { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { - try { this.textarea.focus() } - catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM - } - }; - - TextareaInput.prototype.blur = function () { this.textarea.blur() }; - - TextareaInput.prototype.resetPosition = function () { - this.wrapper.style.top = this.wrapper.style.left = 0 - }; - - TextareaInput.prototype.receivedFocus = function () { this.slowPoll() }; - - // Poll for input changes, using the normal rate of polling. This - // runs as long as the editor is focused. - TextareaInput.prototype.slowPoll = function () { - var this$1 = this; - - if (this.pollingFast) { return } - this.polling.set(this.cm.options.pollInterval, function () { - this$1.poll() - if (this$1.cm.state.focused) { this$1.slowPoll() } - }) - }; - - // When an event has just come in that is likely to add or change - // something in the input textarea, we poll faster, to ensure that - // the change appears on the screen quickly. - TextareaInput.prototype.fastPoll = function () { - var missed = false, input = this - input.pollingFast = true - function p() { - var changed = input.poll() - if (!changed && !missed) {missed = true; input.polling.set(60, p)} - else {input.pollingFast = false; input.slowPoll()} - } - input.polling.set(20, p) - }; - - // Read input from the textarea, and update the document to match. - // When something is selected, it is present in the textarea, and - // selected (unless it is huge, in which case a placeholder is - // used). When nothing is selected, the cursor sits after previously - // seen text (can be empty), which is stored in prevInput (we must - // not reset the textarea when typing, because that breaks IME). - TextareaInput.prototype.poll = function () { - var this$1 = this; - - var cm = this.cm, input = this.textarea, prevInput = this.prevInput - // Since this is called a *lot*, try to bail out as cheaply as - // possible when it is clear that nothing happened. hasSelection - // will be the case when there is a lot of text in the textarea, - // in which case reading its value would be expensive. - if (this.contextMenuPending || !cm.state.focused || - (hasSelection(input) && !prevInput && !this.composing) || - cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) - { return false } - - var text = input.value - // If nothing changed, bail. - if (text == prevInput && !cm.somethingSelected()) { return false } - // Work around nonsensical selection resetting in IE9/10, and - // inexplicable appearance of private area unicode characters on - // some key combos in Mac (#2689). - if (ie && ie_version >= 9 && this.hasSelection === text || - mac && /[\uf700-\uf7ff]/.test(text)) { - cm.display.input.reset() - return false - } - - if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0) - if (first == 0x200b && !prevInput) { prevInput = "\u200b" } - if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } - } - // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length) - while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same } - - runInOp(cm, function () { - applyTextInput(cm, text.slice(same), prevInput.length - same, - null, this$1.composing ? "*compose" : null) - - // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" } - else { this$1.prevInput = text } - - if (this$1.composing) { - this$1.composing.range.clear() - this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"), - {className: "CodeMirror-composing"}) - } - }) - return true - }; - - TextareaInput.prototype.ensurePolled = function () { - if (this.pollingFast && this.poll()) { this.pollingFast = false } - }; - - TextareaInput.prototype.onKeyPress = function () { - if (ie && ie_version >= 9) { this.hasSelection = null } - this.fastPoll() - }; - - TextareaInput.prototype.onContextMenu = function (e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop - if (!pos || presto) { return } // Opera is difficult. - - // Reset the current text selection only if the click is done outside of the selection - // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu - if (reset && cm.doc.sel.contains(pos) == -1) - { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) } - - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText - input.wrapper.style.cssText = "position: absolute" - var wrapperBox = input.wrapper.getBoundingClientRect() - te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" - var oldScrollY - if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712) - display.input.focus() - if (webkit) { window.scrollTo(null, oldScrollY) } - display.input.reset() - // Adds "Select all" to context menu in FF - if (!cm.somethingSelected()) { te.value = input.prevInput = " " } - input.contextMenuPending = true - display.selForContextMenu = cm.doc.sel - clearTimeout(display.detectingSelectAll) - - // Select-all will be greyed out if there's nothing to select, so - // this adds a zero-width space so that we can later check whether - // it got selected. - function prepareSelectAllHack() { - if (te.selectionStart != null) { - var selected = cm.somethingSelected() - var extval = "\u200b" + (selected ? te.value : "") - te.value = "\u21da" // Used to catch context-menu undo - te.value = extval - input.prevInput = selected ? "" : "\u200b" - te.selectionStart = 1; te.selectionEnd = extval.length - // Re-set this, in case some other handler touched the - // selection in the meantime. - display.selForContextMenu = cm.doc.sel - } - } - function rehide() { - input.contextMenuPending = false - input.wrapper.style.cssText = oldWrapperCSS - te.style.cssText = oldCSS - if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) } - - // Try to detect the user choosing select-all - if (te.selectionStart != null) { - if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() } - var i = 0, poll = function () { - if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && - te.selectionEnd > 0 && input.prevInput == "\u200b") { - operation(cm, selectAll)(cm) - } else if (i++ < 10) { - display.detectingSelectAll = setTimeout(poll, 500) - } else { - display.selForContextMenu = null - display.input.reset() - } - } - display.detectingSelectAll = setTimeout(poll, 200) - } - } - - if (ie && ie_version >= 9) { prepareSelectAllHack() } - if (captureRightClick) { - e_stop(e) - var mouseup = function () { - off(window, "mouseup", mouseup) - setTimeout(rehide, 20) - } - on(window, "mouseup", mouseup) - } else { - setTimeout(rehide, 50) - } - }; - - TextareaInput.prototype.readOnlyChanged = function (val) { - if (!val) { this.reset() } - this.textarea.disabled = val == "nocursor" - }; - - TextareaInput.prototype.setUneditable = function () {}; - - TextareaInput.prototype.needsContentAttribute = false - - function fromTextArea(textarea, options) { - options = options ? copyObj(options) : {} - options.value = textarea.value - if (!options.tabindex && textarea.tabIndex) - { options.tabindex = textarea.tabIndex } - if (!options.placeholder && textarea.placeholder) - { options.placeholder = textarea.placeholder } - // Set autofocus to true if this textarea is focused, or if it has - // autofocus and no other element is focused. - if (options.autofocus == null) { - var hasFocus = activeElt() - options.autofocus = hasFocus == textarea || - textarea.getAttribute("autofocus") != null && hasFocus == document.body - } - - function save() {textarea.value = cm.getValue()} - - var realSubmit - if (textarea.form) { - on(textarea.form, "submit", save) - // Deplorable hack to make the submit method do the right thing. - if (!options.leaveSubmitMethodAlone) { - var form = textarea.form - realSubmit = form.submit - try { - var wrappedSubmit = form.submit = function () { - save() - form.submit = realSubmit - form.submit() - form.submit = wrappedSubmit - } - } catch(e) {} - } - } - - options.finishInit = function (cm) { - cm.save = save - cm.getTextArea = function () { return textarea; } - cm.toTextArea = function () { - cm.toTextArea = isNaN // Prevent this from being ran twice - save() - textarea.parentNode.removeChild(cm.getWrapperElement()) - textarea.style.display = "" - if (textarea.form) { - off(textarea.form, "submit", save) - if (typeof textarea.form.submit == "function") - { textarea.form.submit = realSubmit } - } - } - } - - textarea.style.display = "none" - var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); }, - options) - return cm - } - - function addLegacyProps(CodeMirror) { - CodeMirror.off = off - CodeMirror.on = on - CodeMirror.wheelEventPixels = wheelEventPixels - CodeMirror.Doc = Doc - CodeMirror.splitLines = splitLinesAuto - CodeMirror.countColumn = countColumn - CodeMirror.findColumn = findColumn - CodeMirror.isWordChar = isWordCharBasic - CodeMirror.Pass = Pass - CodeMirror.signal = signal - CodeMirror.Line = Line - CodeMirror.changeEnd = changeEnd - CodeMirror.scrollbarModel = scrollbarModel - CodeMirror.Pos = Pos - CodeMirror.cmpPos = cmp - CodeMirror.modes = modes - CodeMirror.mimeModes = mimeModes - CodeMirror.resolveMode = resolveMode - CodeMirror.getMode = getMode - CodeMirror.modeExtensions = modeExtensions - CodeMirror.extendMode = extendMode - CodeMirror.copyState = copyState - CodeMirror.startState = startState - CodeMirror.innerMode = innerMode - CodeMirror.commands = commands - CodeMirror.keyMap = keyMap - CodeMirror.keyName = keyName - CodeMirror.isModifierKey = isModifierKey - CodeMirror.lookupKey = lookupKey - CodeMirror.normalizeKeyMap = normalizeKeyMap - CodeMirror.StringStream = StringStream - CodeMirror.SharedTextMarker = SharedTextMarker - CodeMirror.TextMarker = TextMarker - CodeMirror.LineWidget = LineWidget - CodeMirror.e_preventDefault = e_preventDefault - CodeMirror.e_stopPropagation = e_stopPropagation - CodeMirror.e_stop = e_stop - CodeMirror.addClass = addClass - CodeMirror.contains = contains - CodeMirror.rmClass = rmClass - CodeMirror.keyNames = keyNames - } - - // EDITOR CONSTRUCTOR - - defineOptions(CodeMirror) - - addEditorMethods(CodeMirror) - - // Set up methods on CodeMirror's prototype to redirect to the editor's document. - var dontDelegate = "iter insert remove copy getEditor constructor".split(" ") - for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) - { CodeMirror.prototype[prop] = (function(method) { - return function() {return method.apply(this.doc, arguments)} - })(Doc.prototype[prop]) } } - - eventMixin(Doc) - - // INPUT HANDLING - - CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} - - // MODE DEFINITION AND QUERYING - - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - CodeMirror.defineMode = function(name/*, mode, …*/) { - if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name } - defineMode.apply(this, arguments) - } - - CodeMirror.defineMIME = defineMIME - - // Minimal default mode. - CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }) - CodeMirror.defineMIME("text/plain", "null") - - // EXTENSIONS - - CodeMirror.defineExtension = function (name, func) { - CodeMirror.prototype[name] = func - } - CodeMirror.defineDocExtension = function (name, func) { - Doc.prototype[name] = func - } - - CodeMirror.fromTextArea = fromTextArea - - addLegacyProps(CodeMirror) - - CodeMirror.version = "5.37.0" - - return CodeMirror; - - }))); - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)) - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod) - else // Plain browser env - mod(CodeMirror) - })(function(CodeMirror) { - "use strict" - var Pos = CodeMirror.Pos - - function regexpFlags(regexp) { - var flags = regexp.flags - return flags != null ? flags : (regexp.ignoreCase ? "i" : "") - + (regexp.global ? "g" : "") - + (regexp.multiline ? "m" : "") - } - - function ensureFlags(regexp, flags) { - var current = regexpFlags(regexp), target = current - for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) - target += flags.charAt(i) - return current == target ? regexp : new RegExp(regexp.source, target) - } - - function maybeMultiline(regexp) { - return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source) - } - - function searchRegexpForward(doc, regexp, start) { - regexp = ensureFlags(regexp, "g") - for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { - regexp.lastIndex = ch - var string = doc.getLine(line), match = regexp.exec(string) - if (match) - return {from: Pos(line, match.index), - to: Pos(line, match.index + match[0].length), - match: match} - } - } - - function searchRegexpForwardMultiline(doc, regexp, start) { - if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) - - regexp = ensureFlags(regexp, "gm") - var string, chunk = 1 - for (var line = start.line, last = doc.lastLine(); line <= last;) { - // This grows the search buffer in exponentially-sized chunks - // between matches, so that nearby matches are fast and don't - // require concatenating the whole document (in case we're - // searching for something that has tons of matches), but at the - // same time, the amount of retries is limited. - for (var i = 0; i < chunk; i++) { - if (line > last) break - var curLine = doc.getLine(line++) - string = string == null ? curLine : string + "\n" + curLine - } - chunk = chunk * 2 - regexp.lastIndex = start.ch - var match = regexp.exec(string) - if (match) { - var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") - var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length - return {from: Pos(startLine, startCh), - to: Pos(startLine + inside.length - 1, - inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), - match: match} - } - } - } - - function lastMatchIn(string, regexp) { - var cutOff = 0, match - for (;;) { - regexp.lastIndex = cutOff - var newMatch = regexp.exec(string) - if (!newMatch) return match - match = newMatch - cutOff = match.index + (match[0].length || 1) - if (cutOff == string.length) return match - } - } - - function searchRegexpBackward(doc, regexp, start) { - regexp = ensureFlags(regexp, "g") - for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { - var string = doc.getLine(line) - if (ch > -1) string = string.slice(0, ch) - var match = lastMatchIn(string, regexp) - if (match) - return {from: Pos(line, match.index), - to: Pos(line, match.index + match[0].length), - match: match} - } - } - - function searchRegexpBackwardMultiline(doc, regexp, start) { - regexp = ensureFlags(regexp, "gm") - var string, chunk = 1 - for (var line = start.line, first = doc.firstLine(); line >= first;) { - for (var i = 0; i < chunk; i++) { - var curLine = doc.getLine(line--) - string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string - } - chunk *= 2 - - var match = lastMatchIn(string, regexp) - if (match) { - var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") - var startLine = line + before.length, startCh = before[before.length - 1].length - return {from: Pos(startLine, startCh), - to: Pos(startLine + inside.length - 1, - inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), - match: match} - } - } - } - - var doFold, noFold - if (String.prototype.normalize) { - doFold = function(str) { return str.normalize("NFD").toLowerCase() } - noFold = function(str) { return str.normalize("NFD") } - } else { - doFold = function(str) { return str.toLowerCase() } - noFold = function(str) { return str } - } - - // Maps a position in a case-folded line back to a position in the original line - // (compensating for codepoints increasing in number during folding) - function adjustPos(orig, folded, pos, foldFunc) { - if (orig.length == folded.length) return pos - for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) { - if (min == max) return min - var mid = (min + max) >> 1 - var len = foldFunc(orig.slice(0, mid)).length - if (len == pos) return mid - else if (len > pos) max = mid - else min = mid + 1 - } - } - - function searchStringForward(doc, query, start, caseFold) { - // Empty string would match anything and never progress, so we - // define it to match nothing instead. - if (!query.length) return null - var fold = caseFold ? doFold : noFold - var lines = fold(query).split(/\r|\n\r?/) - - search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) { - var orig = doc.getLine(line).slice(ch), string = fold(orig) - if (lines.length == 1) { - var found = string.indexOf(lines[0]) - if (found == -1) continue search - var start = adjustPos(orig, string, found, fold) + ch - return {from: Pos(line, adjustPos(orig, string, found, fold) + ch), - to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)} - } else { - var cutFrom = string.length - lines[0].length - if (string.slice(cutFrom) != lines[0]) continue search - for (var i = 1; i < lines.length - 1; i++) - if (fold(doc.getLine(line + i)) != lines[i]) continue search - var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] - if (endString.slice(0, lastLine.length) != lastLine) continue search - return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), - to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} - } - } - } - - function searchStringBackward(doc, query, start, caseFold) { - if (!query.length) return null - var fold = caseFold ? doFold : noFold - var lines = fold(query).split(/\r|\n\r?/) - - search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) { - var orig = doc.getLine(line) - if (ch > -1) orig = orig.slice(0, ch) - var string = fold(orig) - if (lines.length == 1) { - var found = string.lastIndexOf(lines[0]) - if (found == -1) continue search - return {from: Pos(line, adjustPos(orig, string, found, fold)), - to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))} - } else { - var lastLine = lines[lines.length - 1] - if (string.slice(0, lastLine.length) != lastLine) continue search - for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++) - if (fold(doc.getLine(start + i)) != lines[i]) continue search - var top = doc.getLine(line + 1 - lines.length), topString = fold(top) - if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search - return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)), - to: Pos(line, adjustPos(orig, string, lastLine.length, fold))} - } - } - } - - function SearchCursor(doc, query, pos, options) { - this.atOccurrence = false - this.doc = doc - pos = pos ? doc.clipPos(pos) : Pos(0, 0) - this.pos = {from: pos, to: pos} - - var caseFold - if (typeof options == "object") { - caseFold = options.caseFold - } else { // Backwards compat for when caseFold was the 4th argument - caseFold = options - options = null - } - - if (typeof query == "string") { - if (caseFold == null) caseFold = false - this.matches = function(reverse, pos) { - return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) - } - } else { - query = ensureFlags(query, "gm") - if (!options || options.multiline !== false) - this.matches = function(reverse, pos) { - return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) - } - else - this.matches = function(reverse, pos) { - return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos) - } - } - } - - SearchCursor.prototype = { - findNext: function() {return this.find(false)}, - findPrevious: function() {return this.find(true)}, - - find: function(reverse) { - var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) - - // Implements weird auto-growing behavior on null-matches for - // backwards-compatiblity with the vim code (unfortunately) - while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { - if (reverse) { - if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) - else if (result.from.line == this.doc.firstLine()) result = null - else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) - } else { - if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) - else if (result.to.line == this.doc.lastLine()) result = null - else result = this.matches(reverse, Pos(result.to.line + 1, 0)) - } - } - - if (result) { - this.pos = result - this.atOccurrence = true - return this.pos.match || true - } else { - var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0) - this.pos = {from: end, to: end} - return this.atOccurrence = false - } - }, - - from: function() {if (this.atOccurrence) return this.pos.from}, - to: function() {if (this.atOccurrence) return this.pos.to}, - - replace: function(newText, origin) { - if (!this.atOccurrence) return - var lines = CodeMirror.splitLines(newText) - this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin) - this.pos.to = Pos(this.pos.from.line + lines.length - 1, - lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)) - } - } - - CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { - return new SearchCursor(this.doc, query, pos, caseFold) - }) - CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { - return new SearchCursor(this, query, pos, caseFold) - }) - - CodeMirror.defineExtension("selectMatches", function(query, caseFold) { - var ranges = [] - var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold) - while (cur.findNext()) { - if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break - ranges.push({anchor: cur.from(), head: cur.to()}) - } - if (ranges.length) - this.setSelections(ranges, 0) - }) - }); - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - // Define search commands. Depends on dialog.js or another - // implementation of the openDialog method. - - // Replace works a little oddly -- it will do the replace on the next - // Ctrl-G (or whatever is bound to findNext) press. You prevent a - // replace by making sure the match is no longer selected when hitting - // Ctrl-G. - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(3), __webpack_require__(1)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - function searchOverlay(query, caseInsensitive) { - if (typeof query == "string") - query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); - else if (!query.global) - query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); - - return {token: function(stream) { - query.lastIndex = stream.pos; - var match = query.exec(stream.string); - if (match && match.index == stream.pos) { - stream.pos += match[0].length || 1; - return "searching"; - } else if (match) { - stream.pos = match.index; - } else { - stream.skipToEnd(); - } - }}; - } - - function SearchState() { - this.posFrom = this.posTo = this.lastQuery = this.query = null; - this.overlay = null; - } - - function getSearchState(cm) { - return cm.state.search || (cm.state.search = new SearchState()); - } - - function queryCaseInsensitive(query) { - return typeof query == "string" && query == query.toLowerCase(); - } - - function getSearchCursor(cm, query, pos) { - // Heuristic: if the query string is all lowercase, do a case insensitive search. - return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true}); - } - - function persistentDialog(cm, text, deflt, onEnter, onKeyDown) { - cm.openDialog(text, onEnter, { - value: deflt, - selectValueOnOpen: true, - closeOnEnter: false, - onClose: function() { clearSearch(cm); }, - onKeyDown: onKeyDown - }); - } - - function dialog(cm, text, shortText, deflt, f) { - if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); - else f(prompt(shortText, deflt)); - } - - function confirmDialog(cm, text, shortText, fs) { - if (cm.openConfirm) cm.openConfirm(text, fs); - else if (confirm(shortText)) fs[0](); - } - - function parseString(string) { - return string.replace(/\\(.)/g, function(_, ch) { - if (ch == "n") return "\n" - if (ch == "r") return "\r" - return ch - }) - } - - function parseQuery(query) { - var isRE = query.match(/^\/(.*)\/([a-z]*)$/); - if (isRE) { - try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } - catch(e) {} // Not a regular expression after all, do a string search - } else { - query = parseString(query) - } - if (typeof query == "string" ? query == "" : query.test("")) - query = /x^/; - return query; - } - - var queryDialog; - - function startSearch(cm, state, query) { - state.queryText = query; - state.query = parseQuery(query); - cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); - state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); - cm.addOverlay(state.overlay); - if (cm.showMatchesOnScrollbar) { - if (state.annotate) { state.annotate.clear(); state.annotate = null; } - state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); - } - } - - function doSearch(cm, rev, persistent, immediate) { - if (!queryDialog) { - let doc = cm.getWrapperElement().ownerDocument; - let inp = doc.createElement("input"); - - inp.type = "search"; - inp.placeholder = cm.l10n("findCmd.promptMessage"); - inp.style.marginInlineStart = "1em"; - inp.style.marginInlineEnd = "1em"; - inp.style.flexGrow = "1"; - inp.addEventListener("focus", () => inp.select()); - - queryDialog = doc.createElement("div"); - queryDialog.appendChild(inp); - queryDialog.style.display = "flex"; - } - - var state = getSearchState(cm); - if (state.query) return findNext(cm, rev); - var q = cm.getSelection() || state.lastQuery; - if (q instanceof RegExp && q.source == "x^") q = null - if (persistent && cm.openDialog) { - var hiding = null - var searchNext = function(query, event) { - CodeMirror.e_stop(event); - if (!query) return; - if (query != state.queryText) { - startSearch(cm, state, query); - state.posFrom = state.posTo = cm.getCursor(); - } - if (hiding) hiding.style.opacity = 1 - findNext(cm, event.shiftKey, function(_, to) { - var dialog - if (to.line < 3 && document.querySelector && - (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && - dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) - (hiding = dialog).style.opacity = .4 - }) - }; - persistentDialog(cm, queryDialog, q, searchNext, function(event, query) { - var keyName = CodeMirror.keyName(event) - var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName] - if (cmd == "findNext" || cmd == "findPrev" || - cmd == "findPersistentNext" || cmd == "findPersistentPrev") { - CodeMirror.e_stop(event); - startSearch(cm, getSearchState(cm), query); - cm.execCommand(cmd); - } else if (cmd == "find" || cmd == "findPersistent") { - CodeMirror.e_stop(event); - searchNext(query, event); - } - }); - if (immediate && q) { - startSearch(cm, state, q); - findNext(cm, rev); - } - } else { - dialog(cm, queryDialog, "Search for:", q, function(query) { - if (query && !state.query) cm.operation(function() { - startSearch(cm, state, query); - state.posFrom = state.posTo = cm.getCursor(); - findNext(cm, rev); - }); - }); - } - } - - function findNext(cm, rev, callback) {cm.operation(function() { - var state = getSearchState(cm); - var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); - if (!cursor.find(rev)) { - cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); - if (!cursor.find(rev)) return; - } - cm.setSelection(cursor.from(), cursor.to()); - cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); - state.posFrom = cursor.from(); state.posTo = cursor.to(); - if (callback) callback(cursor.from(), cursor.to()) - });} - - function clearSearch(cm) {cm.operation(function() { - var state = getSearchState(cm); - state.lastQuery = state.query; - if (!state.query) return; - state.query = state.queryText = null; - cm.removeOverlay(state.overlay); - if (state.annotate) { state.annotate.clear(); state.annotate = null; } - });} - - function replaceAll(cm, query, text) { - cm.operation(function() { - for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { - if (typeof query != "string") { - var match = cm.getRange(cursor.from(), cursor.to()).match(query); - cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); - } else cursor.replace(text); - } - }); - } - - function replace(cm, all) { - if (cm.getOption("readOnly")) return; - var query = cm.getSelection() || getSearchState(cm).lastQuery; - - let doc = cm.getWrapperElement().ownerDocument; - - // `searchLabel` is used as part of `replaceQueryFragment` and as a separate - // argument by itself, so it should be cloned. - let searchLabel = doc.createElement("span"); - searchLabel.classList.add("CodeMirror-search-label"); - searchLabel.textContent = all ? "Replace all:" : "Replace:"; - - let replaceQueryFragment = doc.createDocumentFragment(); - replaceQueryFragment.appendChild(searchLabel.cloneNode(true)); - - let searchField = doc.createElement("input"); - searchField.setAttribute("type", "text"); - searchField.setAttribute("style", "width: 10em"); - searchField.classList.add("CodeMirror-search-field"); - replaceQueryFragment.appendChild(searchField); - - let searchHint = doc.createElement("span"); - searchHint.setAttribute("style", "color: #888"); - searchHint.classList.add("CodeMirror-search-hint"); - searchHint.textContent = "(Use /re/ syntax for regexp search)"; - replaceQueryFragment.appendChild(searchHint); - - dialog(cm, replaceQueryFragment, searchLabel, query, function(query) { - if (!query) return; - query = parseQuery(query); - - let replacementQueryFragment = doc.createDocumentFragment(); - - let replaceWithLabel = searchLabel.cloneNode(false); - replaceWithLabel.textContent = "With:"; - replacementQueryFragment.appendChild(replaceWithLabel); - - let replaceField = doc.createElement("input"); - replaceField.setAttribute("type", "text"); - replaceField.setAttribute("style", "width: 10em"); - replaceField.classList.add("CodeMirror-search-field"); - replacementQueryFragment.appendChild(replaceField); - - dialog(cm, replacementQueryFragment, "Replace with:", "", function(text) { - text = parseString(text) - if (all) { - replaceAll(cm, query, text) - } else { - clearSearch(cm); - var cursor = getSearchCursor(cm, query, cm.getCursor("from")); - var advance = function() { - var start = cursor.from(), match; - if (!(match = cursor.findNext())) { - cursor = getSearchCursor(cm, query); - if (!(match = cursor.findNext()) || - (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; - } - cm.setSelection(cursor.from(), cursor.to()); - cm.scrollIntoView({ from: cursor.from(), to: cursor.to() }); - - let replaceConfirmFragment = doc.createDocumentFragment(); - - let replaceConfirmLabel = searchLabel.cloneNode(false); - replaceConfirmLabel.textContent = "Replace?"; - replaceConfirmFragment.appendChild(replaceConfirmLabel); - - let yesButton = doc.createElement("button"); - yesButton.textContent = "Yes"; - replaceConfirmFragment.appendChild(yesButton); - - let noButton = doc.createElement("button"); - noButton.textContent = "No"; - replaceConfirmFragment.appendChild(noButton); - - let allButton = doc.createElement("button"); - allButton.textContent = "All"; - replaceConfirmFragment.appendChild(allButton); - - let stopButton = doc.createElement("button"); - stopButton.textContent = "Stop"; - replaceConfirmFragment.appendChild(stopButton); - - confirmDialog(cm, replaceConfirmFragment, "Replace?", - [function() {doReplace(match);}, advance, - function() {replaceAll(cm, query, text)}]); - }; - var doReplace = function(match) { - cursor.replace(typeof query == "string" ? text : - text.replace(/\$(\d)/g, function(_, i) {return match[i];})); - advance(); - }; - advance(); - } - }); - }); - } - - CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; - CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; - CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);}; - CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);}; - CodeMirror.commands.findNext = doSearch; - CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; - CodeMirror.commands.clearSearch = clearSearch; - CodeMirror.commands.replace = replace; - CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; - }); - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && - (document.documentMode == null || document.documentMode < 8); - - var Pos = CodeMirror.Pos; - - var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; - - function findMatchingBracket(cm, where, config) { - var line = cm.getLineHandle(where.line), pos = where.ch - 1; - var afterCursor = config && config.afterCursor - if (afterCursor == null) - afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className) - - // A cursor is defined as between two characters, but in in vim command mode - // (i.e. not insert mode), the cursor is visually represented as a - // highlighted box on top of the 2nd character. Otherwise, we allow matches - // from before or after the cursor. - var match = (!afterCursor && pos >= 0 && matching[line.text.charAt(pos)]) || - matching[line.text.charAt(++pos)]; - if (!match) return null; - var dir = match.charAt(1) == ">" ? 1 : -1; - if (config && config.strict && (dir > 0) != (pos == where.ch)) return null; - var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); - - var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); - if (found == null) return null; - return {from: Pos(where.line, pos), to: found && found.pos, - match: found && found.ch == match.charAt(0), forward: dir > 0}; - } - - // bracketRegex is used to specify which type of bracket to scan - // should be a regexp, e.g. /[[\]]/ - // - // Note: If "where" is on an open bracket, then this bracket is ignored. - // - // Returns false when no bracket was found, null when it reached - // maxScanLines and gave up - function scanForBracket(cm, where, dir, style, config) { - var maxScanLen = (config && config.maxScanLineLength) || 10000; - var maxScanLines = (config && config.maxScanLines) || 1000; - - var stack = []; - var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/; - var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) - : Math.max(cm.firstLine() - 1, where.line - maxScanLines); - for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { - var line = cm.getLine(lineNo); - if (!line) continue; - var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; - if (line.length > maxScanLen) continue; - if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); - for (; pos != end; pos += dir) { - var ch = line.charAt(pos); - if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { - var match = matching[ch]; - if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch); - else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; - else stack.pop(); - } - } - } - return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; - } - - function matchBrackets(cm, autoclear, config) { - // Disable brace matching in long lines, since it'll cause hugely slow updates - var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; - var marks = [], ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config); - if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { - var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; - marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); - if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) - marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); - } - } - - if (marks.length) { - // Kludge to work around the IE bug from issue #1193, where text - // input stops going to the textare whever this fires. - if (ie_lt8 && cm.state.focused) cm.focus(); - - var clear = function() { - cm.operation(function() { - for (var i = 0; i < marks.length; i++) marks[i].clear(); - }); - }; - if (autoclear) setTimeout(clear, 800); - else return clear; - } - } - - function doMatchBrackets(cm) { - cm.operation(function() { - if (cm.state.matchBrackets.currentlyHighlighted) { - cm.state.matchBrackets.currentlyHighlighted(); - cm.state.matchBrackets.currentlyHighlighted = null; - } - cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); - }); - } - - CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { - if (old && old != CodeMirror.Init) { - cm.off("cursorActivity", doMatchBrackets); - if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { - cm.state.matchBrackets.currentlyHighlighted(); - cm.state.matchBrackets.currentlyHighlighted = null; - } - } - if (val) { - cm.state.matchBrackets = typeof val == "object" ? val : {}; - cm.on("cursorActivity", doMatchBrackets); - } - }); - - CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); - CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){ - // Backwards-compatibility kludge - if (oldConfig || typeof config == "boolean") { - if (!oldConfig) { - config = config ? {strict: true} : null - } else { - oldConfig.strict = config - config = oldConfig - } - } - return findMatchingBracket(this, pos, config) - }); - CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ - return scanForBracket(this, pos, dir, style, config); - }); - }); - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - var defaults = { - pairs: "()[]{}''\"\"", - triples: "", - explode: "[]{}" - }; - - var Pos = CodeMirror.Pos; - - CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { - if (old && old != CodeMirror.Init) { - cm.removeKeyMap(keyMap); - cm.state.closeBrackets = null; - } - if (val) { - ensureBound(getOption(val, "pairs")) - cm.state.closeBrackets = val; - cm.addKeyMap(keyMap); - } - }); - - function getOption(conf, name) { - if (name == "pairs" && typeof conf == "string") return conf; - if (typeof conf == "object" && conf[name] != null) return conf[name]; - return defaults[name]; - } - - var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; - function ensureBound(chars) { - for (var i = 0; i < chars.length; i++) { - var ch = chars.charAt(i), key = "'" + ch + "'" - if (!keyMap[key]) keyMap[key] = handler(ch) - } - } - ensureBound(defaults.pairs + "`") - - function handler(ch) { - return function(cm) { return handleChar(cm, ch); }; - } - - function getConfig(cm) { - var deflt = cm.state.closeBrackets; - if (!deflt || deflt.override) return deflt; - var mode = cm.getModeAt(cm.getCursor()); - return mode.closeBrackets || deflt; - } - - function handleBackspace(cm) { - var conf = getConfig(cm); - if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; - - var pairs = getOption(conf, "pairs"); - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) return CodeMirror.Pass; - var around = charsAround(cm, ranges[i].head); - if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; - } - for (var i = ranges.length - 1; i >= 0; i--) { - var cur = ranges[i].head; - cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); - } - } - - function handleEnter(cm) { - var conf = getConfig(cm); - var explode = conf && getOption(conf, "explode"); - if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; - - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) return CodeMirror.Pass; - var around = charsAround(cm, ranges[i].head); - if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; - } - cm.operation(function() { - var linesep = cm.lineSeparator() || "\n"; - cm.replaceSelection(linesep + linesep, null); - cm.execCommand("goCharLeft"); - ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - var line = ranges[i].head.line; - cm.indentLine(line, null, true); - cm.indentLine(line + 1, null, true); - } - }); - } - - function contractSelection(sel) { - var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; - return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), - head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; - } - - function handleChar(cm, ch) { - var conf = getConfig(cm); - if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; - - var pairs = getOption(conf, "pairs"); - var pos = pairs.indexOf(ch); - if (pos == -1) return CodeMirror.Pass; - var triples = getOption(conf, "triples"); - - var identical = pairs.charAt(pos + 1) == ch; - var ranges = cm.listSelections(); - var opening = pos % 2 == 0; - - var type; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i], cur = range.head, curType; - var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); - if (opening && !range.empty()) { - curType = "surround"; - } else if ((identical || !opening) && next == ch) { - if (identical && stringStartsAfter(cm, cur)) - curType = "both"; - else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) - curType = "skipThree"; - else - curType = "skip"; - } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && - cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { - if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; - curType = "addFour"; - } else if (identical) { - var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) - if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; - else return CodeMirror.Pass; - } else if (opening && (cm.getLine(cur.line).length == cur.ch || - isClosingBracket(next, pairs) || - /\s/.test(next))) { - curType = "both"; - } else { - return CodeMirror.Pass; - } - if (!type) type = curType; - else if (type != curType) return CodeMirror.Pass; - } - - var left = pos % 2 ? pairs.charAt(pos - 1) : ch; - var right = pos % 2 ? ch : pairs.charAt(pos + 1); - cm.operation(function() { - if (type == "skip") { - cm.execCommand("goCharRight"); - } else if (type == "skipThree") { - for (var i = 0; i < 3; i++) - cm.execCommand("goCharRight"); - } else if (type == "surround") { - var sels = cm.getSelections(); - for (var i = 0; i < sels.length; i++) - sels[i] = left + sels[i] + right; - cm.replaceSelections(sels, "around"); - sels = cm.listSelections().slice(); - for (var i = 0; i < sels.length; i++) - sels[i] = contractSelection(sels[i]); - cm.setSelections(sels); - } else if (type == "both") { - cm.replaceSelection(left + right, null); - cm.triggerElectric(left + right); - cm.execCommand("goCharLeft"); - } else if (type == "addFour") { - cm.replaceSelection(left + left + left + left, "before"); - cm.execCommand("goCharRight"); - } - }); - } - - function isClosingBracket(ch, pairs) { - var pos = pairs.lastIndexOf(ch); - return pos > -1 && pos % 2 == 1; - } - - function charsAround(cm, pos) { - var str = cm.getRange(Pos(pos.line, pos.ch - 1), - Pos(pos.line, pos.ch + 1)); - return str.length == 2 ? str : null; - } - - function stringStartsAfter(cm, pos) { - var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) - return /\bstring/.test(token.type) && token.start == pos.ch && - (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) - } - }); - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var noOptions = {}; - var nonWS = /[^\s\u00a0]/; - var Pos = CodeMirror.Pos; - - function firstNonWS(str) { - var found = str.search(nonWS); - return found == -1 ? 0 : found; - } - - CodeMirror.commands.toggleComment = function(cm) { - cm.toggleComment(); - }; - - CodeMirror.defineExtension("toggleComment", function(options) { - if (!options) options = noOptions; - var cm = this; - var minLine = Infinity, ranges = this.listSelections(), mode = null; - for (var i = ranges.length - 1; i >= 0; i--) { - var from = ranges[i].from(), to = ranges[i].to(); - if (from.line >= minLine) continue; - if (to.line >= minLine) to = Pos(minLine, 0); - minLine = from.line; - if (mode == null) { - if (cm.uncomment(from, to, options)) mode = "un"; - else { cm.lineComment(from, to, options); mode = "line"; } - } else if (mode == "un") { - cm.uncomment(from, to, options); - } else { - cm.lineComment(from, to, options); - } - } - }); - - // Rough heuristic to try and detect lines that are part of multi-line string - function probablyInsideString(cm, pos, line) { - return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line) - } - - function getMode(cm, pos) { - var mode = cm.getMode() - return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos) - } - - CodeMirror.defineExtension("lineComment", function(from, to, options) { - if (!options) options = noOptions; - var self = this, mode = getMode(self, from); - var firstLine = self.getLine(from.line); - if (firstLine == null || probablyInsideString(self, from, firstLine)) return; - - var commentString = options.lineComment || mode.lineComment; - if (!commentString) { - if (options.blockCommentStart || mode.blockCommentStart) { - options.fullLines = true; - self.blockComment(from, to, options); - } - return; - } - - var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); - var pad = options.padding == null ? " " : options.padding; - var blankLines = options.commentBlankLines || from.line == to.line; - - self.operation(function() { - if (options.indent) { - var baseString = null; - for (var i = from.line; i < end; ++i) { - var line = self.getLine(i); - var whitespace = line.slice(0, firstNonWS(line)); - if (baseString == null || baseString.length > whitespace.length) { - baseString = whitespace; - } - } - for (var i = from.line; i < end; ++i) { - var line = self.getLine(i), cut = baseString.length; - if (!blankLines && !nonWS.test(line)) continue; - if (line.slice(0, cut) != baseString) cut = firstNonWS(line); - self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); - } - } else { - for (var i = from.line; i < end; ++i) { - if (blankLines || nonWS.test(self.getLine(i))) - self.replaceRange(commentString + pad, Pos(i, 0)); - } - } - }); - }); - - CodeMirror.defineExtension("blockComment", function(from, to, options) { - if (!options) options = noOptions; - var self = this, mode = getMode(self, from); - var startString = options.blockCommentStart || mode.blockCommentStart; - var endString = options.blockCommentEnd || mode.blockCommentEnd; - if (!startString || !endString) { - if ((options.lineComment || mode.lineComment) && options.fullLines != false) - self.lineComment(from, to, options); - return; - } - if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return - - var end = Math.min(to.line, self.lastLine()); - if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; - - var pad = options.padding == null ? " " : options.padding; - if (from.line > end) return; - - self.operation(function() { - if (options.fullLines != false) { - var lastLineHasText = nonWS.test(self.getLine(end)); - self.replaceRange(pad + endString, Pos(end)); - self.replaceRange(startString + pad, Pos(from.line, 0)); - var lead = options.blockCommentLead || mode.blockCommentLead; - if (lead != null) for (var i = from.line + 1; i <= end; ++i) - if (i != end || lastLineHasText) - self.replaceRange(lead + pad, Pos(i, 0)); - } else { - self.replaceRange(endString, to); - self.replaceRange(startString, from); - } - }); - }); - - CodeMirror.defineExtension("uncomment", function(from, to, options) { - if (!options) options = noOptions; - var self = this, mode = getMode(self, from); - var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); - - // Try finding line comments - var lineString = options.lineComment || mode.lineComment, lines = []; - var pad = options.padding == null ? " " : options.padding, didSomething; - lineComment: { - if (!lineString) break lineComment; - for (var i = start; i <= end; ++i) { - var line = self.getLine(i); - var found = line.indexOf(lineString); - if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; - if (found == -1 && nonWS.test(line)) break lineComment; - if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; - lines.push(line); - } - self.operation(function() { - for (var i = start; i <= end; ++i) { - var line = lines[i - start]; - var pos = line.indexOf(lineString), endPos = pos + lineString.length; - if (pos < 0) continue; - if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; - didSomething = true; - self.replaceRange("", Pos(i, pos), Pos(i, endPos)); - } - }); - if (didSomething) return true; - } - - // Try block comments - var startString = options.blockCommentStart || mode.blockCommentStart; - var endString = options.blockCommentEnd || mode.blockCommentEnd; - if (!startString || !endString) return false; - var lead = options.blockCommentLead || mode.blockCommentLead; - var startLine = self.getLine(start), open = startLine.indexOf(startString) - if (open == -1) return false - var endLine = end == start ? startLine : self.getLine(end) - var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); - var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1) - if (close == -1 || - !/comment/.test(self.getTokenTypeAt(insideStart)) || - !/comment/.test(self.getTokenTypeAt(insideEnd)) || - self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1) - return false; - - // Avoid killing block comments completely outside the selection. - // Positions of the last startString before the start of the selection, and the first endString after it. - var lastStart = startLine.lastIndexOf(startString, from.ch); - var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); - if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; - // Positions of the first endString after the end of the selection, and the last startString before it. - firstEnd = endLine.indexOf(endString, to.ch); - var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); - lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; - if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; - - self.operation(function() { - self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), - Pos(end, close + endString.length)); - var openEnd = open + startString.length; - if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; - self.replaceRange("", Pos(start, open), Pos(start, openEnd)); - if (lead) for (var i = start + 1; i <= end; ++i) { - var line = self.getLine(i), found = line.indexOf(lead); - if (found == -1 || nonWS.test(line.slice(0, found))) continue; - var foundEnd = found + lead.length; - if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; - self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); - } - }); - return true; - }); - }); - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.defineMode("javascript", function(config, parserConfig) { - var indentUnit = config.indentUnit; - var statementIndent = parserConfig.statementIndent; - var jsonldMode = parserConfig.jsonld; - var jsonMode = parserConfig.json || jsonldMode; - var isTS = parserConfig.typescript; - var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - - // Tokenizer - - var keywords = function(){ - function kw(type) {return {type: type, style: "keyword"};} - var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d"); - var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - - return { - "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, - "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C, - "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"), - "function": kw("function"), "catch": kw("catch"), - "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, - "this": kw("this"), "class": kw("class"), "super": kw("atom"), - "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, - "await": C - }; - }(); - - var isOperatorChar = /[+\-*&%=<>!?|~^@]/; - var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; - - function readRegexp(stream) { - var escaped = false, next, inSet = false; - while ((next = stream.next()) != null) { - if (!escaped) { - if (next == "/" && !inSet) return; - if (next == "[") inSet = true; - else if (inSet && next == "]") inSet = false; - } - escaped = !escaped && next == "\\"; - } - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - function ret(tp, style, cont) { - type = tp; content = cont; - return style; - } - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { - return ret("number", "number"); - } else if (ch == "." && stream.match("..")) { - return ret("spread", "meta"); - } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { - return ret(ch); - } else if (ch == "=" && stream.eat(">")) { - return ret("=>", "operator"); - } else if (ch == "0" && stream.eat(/x/i)) { - stream.eatWhile(/[\da-f]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/o/i)) { - stream.eatWhile(/[0-7]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/b/i)) { - stream.eatWhile(/[01]/i); - return ret("number", "number"); - } else if (/\d/.test(ch)) { - stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); - return ret("number", "number"); - } else if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else if (expressionAllowed(stream, state, 1)) { - readRegexp(stream); - stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); - return ret("regexp", "string-2"); - } else { - stream.eat("="); - return ret("operator", "operator", stream.current()); - } - } else if (ch == "`") { - state.tokenize = tokenQuasi; - return tokenQuasi(stream, state); - } else if (ch == "#") { - stream.skipToEnd(); - return ret("error", "error"); - } else if (isOperatorChar.test(ch)) { - if (ch != ">" || !state.lexical || state.lexical.type != ">") { - if (stream.eat("=")) { - if (ch == "!" || ch == "=") stream.eat("=") - } else if (/[<>*+\-]/.test(ch)) { - stream.eat(ch) - if (ch == ">") stream.eat(ch) - } - } - return ret("operator", "operator", stream.current()); - } else if (wordRE.test(ch)) { - stream.eatWhile(wordRE); - var word = stream.current() - if (state.lastType != ".") { - if (keywords.propertyIsEnumerable(word)) { - var kw = keywords[word] - return ret(kw.type, kw.style, word) - } - if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false)) - return ret("async", "keyword", word) - } - return ret("variable", "variable", word) - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next; - if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ - state.tokenize = tokenBase; - return ret("jsonld-keyword", "meta"); - } - while ((next = stream.next()) != null) { - if (next == quote && !escaped) break; - escaped = !escaped && next == "\\"; - } - if (!escaped) state.tokenize = tokenBase; - return ret("string", "string"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenQuasi(stream, state) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next == "\\"; - } - return ret("quasi", "string-2", stream.current()); - } - - var brackets = "([{}])"; - // This is a crude lookahead trick to try and notice that we're - // parsing the argument patterns for a fat-arrow function before we - // actually hit the arrow token. It only works if the arrow is on - // the same line as the arguments and there's no strange noise - // (comments) in between. Fallback is to only notice when we hit the - // arrow, and not declare the arguments as locals for the arrow - // body. - function findFatArrow(stream, state) { - if (state.fatArrowAt) state.fatArrowAt = null; - var arrow = stream.string.indexOf("=>", stream.start); - if (arrow < 0) return; - - if (isTS) { // Try to skip TypeScript return type declarations after the arguments - var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) - if (m) arrow = m.index - } - - var depth = 0, sawSomething = false; - for (var pos = arrow - 1; pos >= 0; --pos) { - var ch = stream.string.charAt(pos); - var bracket = brackets.indexOf(ch); - if (bracket >= 0 && bracket < 3) { - if (!depth) { ++pos; break; } - if (--depth == 0) { if (ch == "(") sawSomething = true; break; } - } else if (bracket >= 3 && bracket < 6) { - ++depth; - } else if (wordRE.test(ch)) { - sawSomething = true; - } else if (/["'\/]/.test(ch)) { - return; - } else if (sawSomething && !depth) { - ++pos; - break; - } - } - if (sawSomething && !depth) state.fatArrowAt = pos; - } - - // Parser - - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; - - function JSLexical(indented, column, type, align, prev, info) { - this.indented = indented; - this.column = column; - this.type = type; - this.prev = prev; - this.info = info; - if (align != null) this.align = align; - } - - function inScope(state, varname) { - for (var v = state.localVars; v; v = v.next) - if (v.name == varname) return true; - for (var cx = state.context; cx; cx = cx.prev) { - for (var v = cx.vars; v; v = v.next) - if (v.name == varname) return true; - } - } - - function parseJS(state, style, type, content, stream) { - var cc = state.cc; - // Communicate our context to the combinators. - // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; - - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = true; - - while(true) { - var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; - if (combinator(type, content)) { - while(cc.length && cc[cc.length - 1].lex) - cc.pop()(); - if (cx.marked) return cx.marked; - if (type == "variable" && inScope(state, content)) return "variable-2"; - return style; - } - } - } - - // Combinator utils - - var cx = {state: null, column: null, marked: null, cc: null}; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); - } - function cont() { - pass.apply(null, arguments); - return true; - } - function register(varname) { - function inList(list) { - for (var v = list; v; v = v.next) - if (v.name == varname) return true; - return false; - } - var state = cx.state; - cx.marked = "def"; - if (state.context) { - if (inList(state.localVars)) return; - state.localVars = {name: varname, next: state.localVars}; - } else { - if (inList(state.globalVars)) return; - if (parserConfig.globalVars) - state.globalVars = {name: varname, next: state.globalVars}; - } - } - - function isModifier(name) { - return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly" - } - - // Combinators - - var defaultVars = {name: "this", next: {name: "arguments"}}; - function pushcontext() { - cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; - cx.state.localVars = defaultVars; - } - function popcontext() { - cx.state.localVars = cx.state.context.vars; - cx.state.context = cx.state.context.prev; - } - function pushlex(type, info) { - var result = function() { - var state = cx.state, indent = state.indented; - if (state.lexical.type == "stat") indent = state.lexical.indented; - else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) - indent = outer.indented; - state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); - }; - result.lex = true; - return result; - } - function poplex() { - var state = cx.state; - if (state.lexical.prev) { - if (state.lexical.type == ")") - state.indented = state.lexical.indented; - state.lexical = state.lexical.prev; - } - } - poplex.lex = true; - - function expect(wanted) { - function exp(type) { - if (type == wanted) return cont(); - else if (wanted == ";") return pass(); - else return cont(exp); - }; - return exp; - } - - function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); - if (type == "keyword b") return cont(pushlex("form"), statement, poplex); - if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); - if (type == "debugger") return cont(expect(";")); - if (type == "{") return cont(pushlex("}"), block, poplex); - if (type == ";") return cont(); - if (type == "if") { - if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) - cx.state.cc.pop()(); - return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); - } - if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); - if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); } - if (type == "variable") { - if (isTS && value == "declare") { - cx.marked = "keyword" - return cont(statement) - } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) { - cx.marked = "keyword" - if (value == "enum") return cont(enumdef); - else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";")); - else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) - } else if (isTS && value == "namespace") { - cx.marked = "keyword" - return cont(pushlex("form"), expression, block, poplex) - } else if (isTS && value == "abstract") { - cx.marked = "keyword" - return cont(statement) - } else { - return cont(pushlex("stat"), maybelabel); - } - } - if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), - block, poplex, poplex); - if (type == "case") return cont(expression, expect(":")); - if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), - statement, poplex, popcontext); - if (type == "export") return cont(pushlex("stat"), afterExport, poplex); - if (type == "import") return cont(pushlex("stat"), afterImport, poplex); - if (type == "async") return cont(statement) - if (value == "@") return cont(expression, statement) - return pass(pushlex("stat"), expression, expect(";"), poplex); - } - function expression(type, value) { - return expressionInner(type, value, false); - } - function expressionNoComma(type, value) { - return expressionInner(type, value, true); - } - function parenExpr(type) { - if (type != "(") return pass() - return cont(pushlex(")"), expression, expect(")"), poplex) - } - function expressionInner(type, value, noComma) { - if (cx.state.fatArrowAt == cx.stream.start) { - var body = noComma ? arrowBodyNoComma : arrowBody; - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); - else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); - } - - var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; - if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef, maybeop); - if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); } - if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); - if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); - if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); - if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); - if (type == "{") return contCommasep(objprop, "}", null, maybeop); - if (type == "quasi") return pass(quasi, maybeop); - if (type == "new") return cont(maybeTarget(noComma)); - if (type == "import") return cont(expression); - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); - return maybeoperatorNoComma(type, value, false); - } - function maybeoperatorNoComma(type, value, noComma) { - var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; - var expr = noComma == false ? expression : expressionNoComma; - if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); - if (type == "operator") { - if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); - if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false)) - return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); - if (value == "?") return cont(expression, expect(":"), expr); - return cont(expr); - } - if (type == "quasi") { return pass(quasi, me); } - if (type == ";") return; - if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); - if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); - if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) } - if (type == "regexp") { - cx.state.lastType = cx.marked = "operator" - cx.stream.backUp(cx.stream.pos - cx.stream.start - 1) - return cont(expr) - } - } - function quasi(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(expression, continueQuasi); - } - function continueQuasi(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasi); - } - } - function arrowBody(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expression); - } - function arrowBodyNoComma(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expressionNoComma); - } - function maybeTarget(noComma) { - return function(type) { - if (type == ".") return cont(noComma ? targetNoComma : target); - else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma) - else return pass(noComma ? expressionNoComma : expression); - }; - } - function target(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } - } - function targetNoComma(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } - } - function maybelabel(type) { - if (type == ":") return cont(poplex, statement); - return pass(maybeoperatorComma, expect(";"), poplex); - } - function property(type) { - if (type == "variable") {cx.marked = "property"; return cont();} - } - function objprop(type, value) { - if (type == "async") { - cx.marked = "property"; - return cont(objprop); - } else if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(getterSetter); - var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params - if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false))) - cx.state.fatArrowAt = cx.stream.pos + m[0].length - return cont(afterprop); - } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (cx.style + " property"); - return cont(afterprop); - } else if (type == "jsonld-keyword") { - return cont(afterprop); - } else if (isTS && isModifier(value)) { - cx.marked = "keyword" - return cont(objprop) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), afterprop); - } else if (type == "spread") { - return cont(expressionNoComma, afterprop); - } else if (value == "*") { - cx.marked = "keyword"; - return cont(objprop); - } else if (type == ":") { - return pass(afterprop) - } - } - function getterSetter(type) { - if (type != "variable") return pass(afterprop); - cx.marked = "property"; - return cont(functiondef); - } - function afterprop(type) { - if (type == ":") return cont(expressionNoComma); - if (type == "(") return pass(functiondef); - } - function commasep(what, end, sep) { - function proceed(type, value) { - if (sep ? sep.indexOf(type) > -1 : type == ",") { - var lex = cx.state.lexical; - if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; - return cont(function(type, value) { - if (type == end || value == end) return pass() - return pass(what) - }, proceed); - } - if (type == end || value == end) return cont(); - return cont(expect(end)); - } - return function(type, value) { - if (type == end || value == end) return cont(); - return pass(what, proceed); - }; - } - function contCommasep(what, end, info) { - for (var i = 3; i < arguments.length; i++) - cx.cc.push(arguments[i]); - return cont(pushlex(end, info), commasep(what, end), poplex); - } - function block(type) { - if (type == "}") return cont(); - return pass(statement, block); - } - function maybetype(type, value) { - if (isTS) { - if (type == ":") return cont(typeexpr); - if (value == "?") return cont(maybetype); - } - } - function mayberettype(type) { - if (isTS && type == ":") { - if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) - else return cont(typeexpr) - } - } - function isKW(_, value) { - if (value == "is") { - cx.marked = "keyword" - return cont() - } - } - function typeexpr(type, value) { - if (value == "keyof" || value == "typeof") { - cx.marked = "keyword" - return cont(value == "keyof" ? typeexpr : expressionNoComma) - } - if (type == "variable" || value == "void") { - cx.marked = "type" - return cont(afterType) - } - if (type == "string" || type == "number" || type == "atom") return cont(afterType); - if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) - if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) - if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) - } - function maybeReturnType(type) { - if (type == "=>") return cont(typeexpr) - } - function typeprop(type, value) { - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property" - return cont(typeprop) - } else if (value == "?") { - return cont(typeprop) - } else if (type == ":") { - return cont(typeexpr) - } else if (type == "[") { - return cont(expression, maybetype, expect("]"), typeprop) - } - } - function typearg(type, value) { - if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg) - if (type == ":") return cont(typeexpr) - return pass(typeexpr) - } - function afterType(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - if (value == "|" || type == "." || value == "&") return cont(typeexpr) - if (type == "[") return cont(expect("]"), afterType) - if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } - } - function maybeTypeArgs(_, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) - } - function typeparam() { - return pass(typeexpr, maybeTypeDefault) - } - function maybeTypeDefault(_, value) { - if (value == "=") return cont(typeexpr) - } - function vardef(_, value) { - if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)} - return pass(pattern, maybetype, maybeAssign, vardefCont); - } - function pattern(type, value) { - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) } - if (type == "variable") { register(value); return cont(); } - if (type == "spread") return cont(pattern); - if (type == "[") return contCommasep(pattern, "]"); - if (type == "{") return contCommasep(proppattern, "}"); - } - function proppattern(type, value) { - if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { - register(value); - return cont(maybeAssign); - } - if (type == "variable") cx.marked = "property"; - if (type == "spread") return cont(pattern); - if (type == "}") return pass(); - return cont(expect(":"), pattern, maybeAssign); - } - function maybeAssign(_type, value) { - if (value == "=") return cont(expressionNoComma); - } - function vardefCont(type) { - if (type == ",") return cont(vardef); - } - function maybeelse(type, value) { - if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); - } - function forspec(type, value) { - if (value == "await") return cont(forspec); - if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, expect(";"), forspec2); - if (type == ";") return cont(forspec2); - if (type == "variable") return cont(formaybeinof); - return pass(expression, expect(";"), forspec2); - } - function formaybeinof(_type, value) { - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return cont(maybeoperatorComma, forspec2); - } - function forspec2(type, value) { - if (type == ";") return cont(forspec3); - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return pass(expression, expect(";"), forspec3); - } - function forspec3(type) { - if (type != ")") cont(expression); - } - function functiondef(type, value) { - if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} - if (type == "variable") {register(value); return cont(functiondef);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) - } - function funarg(type, value) { - if (value == "@") cont(expression, funarg) - if (type == "spread") return cont(funarg); - if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } - return pass(pattern, maybetype, maybeAssign); - } - function classExpression(type, value) { - // Class expressions may have an optional name. - if (type == "variable") return className(type, value); - return classNameAfter(type, value); - } - function className(type, value) { - if (type == "variable") {register(value); return cont(classNameAfter);} - } - function classNameAfter(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) - if (value == "extends" || value == "implements" || (isTS && type == ",")) { - if (value == "implements") cx.marked = "keyword"; - return cont(isTS ? typeexpr : expression, classNameAfter); - } - if (type == "{") return cont(pushlex("}"), classBody, poplex); - } - function classBody(type, value) { - if (type == "async" || - (type == "variable" && - (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && - cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - return cont(isTS ? classfield : functiondef, classBody); - } - if (type == "[") - return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == ";") return cont(classBody); - if (type == "}") return cont(); - if (value == "@") return cont(expression, classBody) - } - function classfield(type, value) { - if (value == "?") return cont(classfield) - if (type == ":") return cont(typeexpr, maybeAssign) - if (value == "=") return cont(expressionNoComma) - return pass(functiondef) - } - function afterExport(type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } - if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } - if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";")); - return pass(statement); - } - function exportField(type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); } - if (type == "variable") return pass(expressionNoComma, exportField); - } - function afterImport(type) { - if (type == "string") return cont(); - if (type == "(") return pass(expression); - return pass(importSpec, maybeMoreImports, maybeFrom); - } - function importSpec(type, value) { - if (type == "{") return contCommasep(importSpec, "}"); - if (type == "variable") register(value); - if (value == "*") cx.marked = "keyword"; - return cont(maybeAs); - } - function maybeMoreImports(type) { - if (type == ",") return cont(importSpec, maybeMoreImports) - } - function maybeAs(_type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } - } - function maybeFrom(_type, value) { - if (value == "from") { cx.marked = "keyword"; return cont(expression); } - } - function arrayLiteral(type) { - if (type == "]") return cont(); - return pass(commasep(expressionNoComma, "]")); - } - function enumdef() { - return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex) - } - function enummember() { - return pass(pattern, maybeAssign); - } - - function isContinuedStatement(state, textAfter) { - return state.lastType == "operator" || state.lastType == "," || - isOperatorChar.test(textAfter.charAt(0)) || - /[,.]/.test(textAfter.charAt(0)); - } - - function expressionAllowed(stream, state, backUp) { - return state.tokenize == tokenBase && - /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) || - (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) - } - - // Interface - - return { - startState: function(basecolumn) { - var state = { - tokenize: tokenBase, - lastType: "sof", - cc: [], - lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), - localVars: parserConfig.localVars, - context: parserConfig.localVars && {vars: parserConfig.localVars}, - indented: basecolumn || 0 - }; - if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") - state.globalVars = parserConfig.globalVars; - return state; - }, - - token: function(stream, state) { - if (stream.sol()) { - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = false; - state.indented = stream.indentation(); - findFatArrow(stream, state); - } - if (state.tokenize != tokenComment && stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - if (type == "comment") return style; - state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; - return parseJS(state, style, type, content, stream); - }, - - indent: function(state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; - if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top - // Kludge to prevent 'maybelse' from blocking lexical scope pops - if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { - var c = state.cc[i]; - if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse) break; - } - while ((lexical.type == "stat" || lexical.type == "form") && - (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && - (top == maybeoperatorComma || top == maybeoperatorNoComma) && - !/^[,\.=+\-*:?[\(]/.test(textAfter)))) - lexical = lexical.prev; - if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") - lexical = lexical.prev; - var type = lexical.type, closing = firstChar == type; - - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); - else if (type == "form" && firstChar == "{") return lexical.indented; - else if (type == "form") return lexical.indented + indentUnit; - else if (type == "stat") - return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); - else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) - return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); - else if (lexical.align) return lexical.column + (closing ? 0 : 1); - else return lexical.indented + (closing ? 0 : indentUnit); - }, - - electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, - blockCommentStart: jsonMode ? null : "/*", - blockCommentEnd: jsonMode ? null : "*/", - blockCommentContinue: jsonMode ? null : " * ", - lineComment: jsonMode ? null : "//", - fold: "brace", - closeBrackets: "()[]{}''\"\"``", - - helperType: jsonMode ? "json" : "javascript", - jsonldMode: jsonldMode, - jsonMode: jsonMode, - - expressionAllowed: expressionAllowed, - - skipExpression: function(state) { - var top = state.cc[state.cc.length - 1] - if (top == expression || top == expressionNoComma) state.cc.pop() - } - }; - }); - - CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); - - CodeMirror.defineMIME("text/javascript", "javascript"); - CodeMirror.defineMIME("text/ecmascript", "javascript"); - CodeMirror.defineMIME("application/javascript", "javascript"); - CodeMirror.defineMIME("application/x-javascript", "javascript"); - CodeMirror.defineMIME("application/ecmascript", "javascript"); - CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); - CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); - CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); - CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); - CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); - - }); - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var htmlConfig = { - autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, - 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, - 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, - 'track': true, 'wbr': true, 'menuitem': true}, - implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, - 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, - 'th': true, 'tr': true}, - contextGrabbers: { - 'dd': {'dd': true, 'dt': true}, - 'dt': {'dd': true, 'dt': true}, - 'li': {'li': true}, - 'option': {'option': true, 'optgroup': true}, - 'optgroup': {'optgroup': true}, - 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, - 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, - 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, - 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, - 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, - 'rp': {'rp': true, 'rt': true}, - 'rt': {'rp': true, 'rt': true}, - 'tbody': {'tbody': true, 'tfoot': true}, - 'td': {'td': true, 'th': true}, - 'tfoot': {'tbody': true}, - 'th': {'td': true, 'th': true}, - 'thead': {'tbody': true, 'tfoot': true}, - 'tr': {'tr': true} - }, - doNotIndent: {"pre": true}, - allowUnquoted: true, - allowMissing: true, - caseFold: true - } - - var xmlConfig = { - autoSelfClosers: {}, - implicitlyClosed: {}, - contextGrabbers: {}, - doNotIndent: {}, - allowUnquoted: false, - allowMissing: false, - allowMissingTagName: false, - caseFold: false - } - - CodeMirror.defineMode("xml", function(editorConf, config_) { - var indentUnit = editorConf.indentUnit - var config = {} - var defaults = config_.htmlMode ? htmlConfig : xmlConfig - for (var prop in defaults) config[prop] = defaults[prop] - for (var prop in config_) config[prop] = config_[prop] - - // Return variables for tokenizers - var type, setStyle; - - function inText(stream, state) { - function chain(parser) { - state.tokenize = parser; - return parser(stream, state); - } - - var ch = stream.next(); - if (ch == "<") { - if (stream.eat("!")) { - if (stream.eat("[")) { - if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); - else return null; - } else if (stream.match("--")) { - return chain(inBlock("comment", "-->")); - } else if (stream.match("DOCTYPE", true, true)) { - stream.eatWhile(/[\w\._\-]/); - return chain(doctype(1)); - } else { - return null; - } - } else if (stream.eat("?")) { - stream.eatWhile(/[\w\._\-]/); - state.tokenize = inBlock("meta", "?>"); - return "meta"; - } else { - type = stream.eat("/") ? "closeTag" : "openTag"; - state.tokenize = inTag; - return "tag bracket"; - } - } else if (ch == "&") { - var ok; - if (stream.eat("#")) { - if (stream.eat("x")) { - ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); - } else { - ok = stream.eatWhile(/[\d]/) && stream.eat(";"); - } - } else { - ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); - } - return ok ? "atom" : "error"; - } else { - stream.eatWhile(/[^&<]/); - return null; - } - } - inText.isInText = true; - - function inTag(stream, state) { - var ch = stream.next(); - if (ch == ">" || (ch == "/" && stream.eat(">"))) { - state.tokenize = inText; - type = ch == ">" ? "endTag" : "selfcloseTag"; - return "tag bracket"; - } else if (ch == "=") { - type = "equals"; - return null; - } else if (ch == "<") { - state.tokenize = inText; - state.state = baseState; - state.tagName = state.tagStart = null; - var next = state.tokenize(stream, state); - return next ? next + " tag error" : "tag error"; - } else if (/[\'\"]/.test(ch)) { - state.tokenize = inAttribute(ch); - state.stringStartCol = stream.column(); - return state.tokenize(stream, state); - } else { - stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); - return "word"; - } - } - - function inAttribute(quote) { - var closure = function(stream, state) { - while (!stream.eol()) { - if (stream.next() == quote) { - state.tokenize = inTag; - break; - } - } - return "string"; - }; - closure.isInAttribute = true; - return closure; - } - - function inBlock(style, terminator) { - return function(stream, state) { - while (!stream.eol()) { - if (stream.match(terminator)) { - state.tokenize = inText; - break; - } - stream.next(); - } - return style; - }; - } - function doctype(depth) { - return function(stream, state) { - var ch; - while ((ch = stream.next()) != null) { - if (ch == "<") { - state.tokenize = doctype(depth + 1); - return state.tokenize(stream, state); - } else if (ch == ">") { - if (depth == 1) { - state.tokenize = inText; - break; - } else { - state.tokenize = doctype(depth - 1); - return state.tokenize(stream, state); - } - } - } - return "meta"; - }; - } - - function Context(state, tagName, startOfLine) { - this.prev = state.context; - this.tagName = tagName; - this.indent = state.indented; - this.startOfLine = startOfLine; - if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) - this.noIndent = true; - } - function popContext(state) { - if (state.context) state.context = state.context.prev; - } - function maybePopContext(state, nextTagName) { - var parentTagName; - while (true) { - if (!state.context) { - return; - } - parentTagName = state.context.tagName; - if (!config.contextGrabbers.hasOwnProperty(parentTagName) || - !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { - return; - } - popContext(state); - } - } - - function baseState(type, stream, state) { - if (type == "openTag") { - state.tagStart = stream.column(); - return tagNameState; - } else if (type == "closeTag") { - return closeTagNameState; - } else { - return baseState; - } - } - function tagNameState(type, stream, state) { - if (type == "word") { - state.tagName = stream.current(); - setStyle = "tag"; - return attrState; - } else if (config.allowMissingTagName && type == "endTag") { - setStyle = "tag bracket"; - return attrState(type, stream, state); - } else { - setStyle = "error"; - return tagNameState; - } - } - function closeTagNameState(type, stream, state) { - if (type == "word") { - var tagName = stream.current(); - if (state.context && state.context.tagName != tagName && - config.implicitlyClosed.hasOwnProperty(state.context.tagName)) - popContext(state); - if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { - setStyle = "tag"; - return closeState; - } else { - setStyle = "tag error"; - return closeStateErr; - } - } else if (config.allowMissingTagName && type == "endTag") { - setStyle = "tag bracket"; - return closeState(type, stream, state); - } else { - setStyle = "error"; - return closeStateErr; - } - } - - function closeState(type, _stream, state) { - if (type != "endTag") { - setStyle = "error"; - return closeState; - } - popContext(state); - return baseState; - } - function closeStateErr(type, stream, state) { - setStyle = "error"; - return closeState(type, stream, state); - } - - function attrState(type, _stream, state) { - if (type == "word") { - setStyle = "attribute"; - return attrEqState; - } else if (type == "endTag" || type == "selfcloseTag") { - var tagName = state.tagName, tagStart = state.tagStart; - state.tagName = state.tagStart = null; - if (type == "selfcloseTag" || - config.autoSelfClosers.hasOwnProperty(tagName)) { - maybePopContext(state, tagName); - } else { - maybePopContext(state, tagName); - state.context = new Context(state, tagName, tagStart == state.indented); - } - return baseState; - } - setStyle = "error"; - return attrState; - } - function attrEqState(type, stream, state) { - if (type == "equals") return attrValueState; - if (!config.allowMissing) setStyle = "error"; - return attrState(type, stream, state); - } - function attrValueState(type, stream, state) { - if (type == "string") return attrContinuedState; - if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;} - setStyle = "error"; - return attrState(type, stream, state); - } - function attrContinuedState(type, stream, state) { - if (type == "string") return attrContinuedState; - return attrState(type, stream, state); - } - - return { - startState: function(baseIndent) { - var state = {tokenize: inText, - state: baseState, - indented: baseIndent || 0, - tagName: null, tagStart: null, - context: null} - if (baseIndent != null) state.baseIndent = baseIndent - return state - }, - - token: function(stream, state) { - if (!state.tagName && stream.sol()) - state.indented = stream.indentation(); - - if (stream.eatSpace()) return null; - type = null; - var style = state.tokenize(stream, state); - if ((style || type) && style != "comment") { - setStyle = null; - state.state = state.state(type || style, stream, state); - if (setStyle) - style = setStyle == "error" ? style + " error" : setStyle; - } - return style; - }, - - indent: function(state, textAfter, fullLine) { - var context = state.context; - // Indent multi-line strings (e.g. css). - if (state.tokenize.isInAttribute) { - if (state.tagStart == state.indented) - return state.stringStartCol + 1; - else - return state.indented + indentUnit; - } - if (context && context.noIndent) return CodeMirror.Pass; - if (state.tokenize != inTag && state.tokenize != inText) - return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; - // Indent the starts of attribute names. - if (state.tagName) { - if (config.multilineTagIndentPastTag !== false) - return state.tagStart + state.tagName.length + 2; - else - return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); - } - if (config.alignCDATA && /$/, - blockCommentStart: "", - - configuration: config.htmlMode ? "html" : "xml", - helperType: config.htmlMode ? "html" : "xml", - - skipAttribute: function(state) { - if (state.state == attrValueState) - state.state = attrState - } - }; - }); - - CodeMirror.defineMIME("text/xml", "xml"); - CodeMirror.defineMIME("application/xml", "xml"); - if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) - CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); - - }); - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.defineMode("css", function(config, parserConfig) { - var inline = parserConfig.inline - if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); - - var indentUnit = config.indentUnit, - tokenHooks = parserConfig.tokenHooks, - documentTypes = parserConfig.documentTypes || {}, - mediaTypes = parserConfig.mediaTypes || {}, - mediaFeatures = parserConfig.mediaFeatures || {}, - mediaValueKeywords = parserConfig.mediaValueKeywords || {}, - propertyKeywords = parserConfig.propertyKeywords || {}, - nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, - fontProperties = parserConfig.fontProperties || {}, - counterDescriptors = parserConfig.counterDescriptors || {}, - colorKeywords = parserConfig.colorKeywords || {}, - valueKeywords = parserConfig.valueKeywords || {}, - allowNested = parserConfig.allowNested, - lineComment = parserConfig.lineComment, - supportsAtComponent = parserConfig.supportsAtComponent === true; - - var type, override; - function ret(style, tp) { type = tp; return style; } - - // Tokenizers - - function tokenBase(stream, state) { - var ch = stream.next(); - if (tokenHooks[ch]) { - var result = tokenHooks[ch](stream, state); - if (result !== false) return result; - } - if (ch == "@") { - stream.eatWhile(/[\w\\\-]/); - return ret("def", stream.current()); - } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { - return ret(null, "compare"); - } else if (ch == "\"" || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "#") { - stream.eatWhile(/[\w\\\-]/); - return ret("atom", "hash"); - } else if (ch == "!") { - stream.match(/^\s*\w*/); - return ret("keyword", "important"); - } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { - stream.eatWhile(/[\w.%]/); - return ret("number", "unit"); - } else if (ch === "-") { - if (/[\d.]/.test(stream.peek())) { - stream.eatWhile(/[\w.%]/); - return ret("number", "unit"); - } else if (stream.match(/^-[\w\\\-]+/)) { - stream.eatWhile(/[\w\\\-]/); - if (stream.match(/^\s*:/, false)) - return ret("variable-2", "variable-definition"); - return ret("variable-2", "variable"); - } else if (stream.match(/^\w+-/)) { - return ret("meta", "meta"); - } - } else if (/[,+>*\/]/.test(ch)) { - return ret(null, "select-op"); - } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { - return ret("qualifier", "qualifier"); - } else if (/[:;{}\[\]\(\)]/.test(ch)) { - return ret(null, ch); - } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) || - ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) || - ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) { - stream.backUp(1); - state.tokenize = tokenParenthesized; - return ret("property", "word"); - } else if (/[\w\\\-]/.test(ch)) { - stream.eatWhile(/[\w\\\-]/); - return ret("property", "word"); - } else { - return ret(null, null); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, ch; - while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - if (quote == ")") stream.backUp(1); - break; - } - escaped = !escaped && ch == "\\"; - } - if (ch == quote || !escaped && quote != ")") state.tokenize = null; - return ret("string", "string"); - }; - } - - function tokenParenthesized(stream, state) { - stream.next(); // Must be '(' - if (!stream.match(/\s*[\"\')]/, false)) - state.tokenize = tokenString(")"); - else - state.tokenize = null; - return ret(null, "("); - } - - // Context management - - function Context(type, indent, prev) { - this.type = type; - this.indent = indent; - this.prev = prev; - } - - function pushContext(state, stream, type, indent) { - state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); - return type; - } - - function popContext(state) { - if (state.context.prev) - state.context = state.context.prev; - return state.context.type; - } - - function pass(type, stream, state) { - return states[state.context.type](type, stream, state); - } - function popAndPass(type, stream, state, n) { - for (var i = n || 1; i > 0; i--) - state.context = state.context.prev; - return pass(type, stream, state); - } - - // Parser - - function wordAsValue(stream) { - var word = stream.current().toLowerCase(); - if (valueKeywords.hasOwnProperty(word)) - override = "atom"; - else if (colorKeywords.hasOwnProperty(word)) - override = "keyword"; - else - override = "variable"; - } - - var states = {}; - - states.top = function(type, stream, state) { - if (type == "{") { - return pushContext(state, stream, "block"); - } else if (type == "}" && state.context.prev) { - return popContext(state); - } else if (supportsAtComponent && /@component/i.test(type)) { - return pushContext(state, stream, "atComponentBlock"); - } else if (/^@(-moz-)?document$/i.test(type)) { - return pushContext(state, stream, "documentTypes"); - } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { - return pushContext(state, stream, "atBlock"); - } else if (/^@(font-face|counter-style)/i.test(type)) { - state.stateArg = type; - return "restricted_atBlock_before"; - } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { - return "keyframes"; - } else if (type && type.charAt(0) == "@") { - return pushContext(state, stream, "at"); - } else if (type == "hash") { - override = "builtin"; - } else if (type == "word") { - override = "tag"; - } else if (type == "variable-definition") { - return "maybeprop"; - } else if (type == "interpolation") { - return pushContext(state, stream, "interpolation"); - } else if (type == ":") { - return "pseudo"; - } else if (allowNested && type == "(") { - return pushContext(state, stream, "parens"); - } - return state.context.type; - }; - - states.block = function(type, stream, state) { - if (type == "word") { - var word = stream.current().toLowerCase(); - if (propertyKeywords.hasOwnProperty(word)) { - override = "property"; - return "maybeprop"; - } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { - override = "string-2"; - return "maybeprop"; - } else if (allowNested) { - override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; - return "block"; - } else { - override += " error"; - return "maybeprop"; - } - } else if (type == "meta") { - return "block"; - } else if (!allowNested && (type == "hash" || type == "qualifier")) { - override = "error"; - return "block"; - } else { - return states.top(type, stream, state); - } - }; - - states.maybeprop = function(type, stream, state) { - if (type == ":") return pushContext(state, stream, "prop"); - return pass(type, stream, state); - }; - - states.prop = function(type, stream, state) { - if (type == ";") return popContext(state); - if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); - if (type == "}" || type == "{") return popAndPass(type, stream, state); - if (type == "(") return pushContext(state, stream, "parens"); - - if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { - override += " error"; - } else if (type == "word") { - wordAsValue(stream); - } else if (type == "interpolation") { - return pushContext(state, stream, "interpolation"); - } - return "prop"; - }; - - states.propBlock = function(type, _stream, state) { - if (type == "}") return popContext(state); - if (type == "word") { override = "property"; return "maybeprop"; } - return state.context.type; - }; - - states.parens = function(type, stream, state) { - if (type == "{" || type == "}") return popAndPass(type, stream, state); - if (type == ")") return popContext(state); - if (type == "(") return pushContext(state, stream, "parens"); - if (type == "interpolation") return pushContext(state, stream, "interpolation"); - if (type == "word") wordAsValue(stream); - return "parens"; - }; - - states.pseudo = function(type, stream, state) { - if (type == "meta") return "pseudo"; - - if (type == "word") { - override = "variable-3"; - return state.context.type; - } - return pass(type, stream, state); - }; - - states.documentTypes = function(type, stream, state) { - if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { - override = "tag"; - return state.context.type; - } else { - return states.atBlock(type, stream, state); - } - }; - - states.atBlock = function(type, stream, state) { - if (type == "(") return pushContext(state, stream, "atBlock_parens"); - if (type == "}" || type == ";") return popAndPass(type, stream, state); - if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); - - if (type == "interpolation") return pushContext(state, stream, "interpolation"); - - if (type == "word") { - var word = stream.current().toLowerCase(); - if (word == "only" || word == "not" || word == "and" || word == "or") - override = "keyword"; - else if (mediaTypes.hasOwnProperty(word)) - override = "attribute"; - else if (mediaFeatures.hasOwnProperty(word)) - override = "property"; - else if (mediaValueKeywords.hasOwnProperty(word)) - override = "keyword"; - else if (propertyKeywords.hasOwnProperty(word)) - override = "property"; - else if (nonStandardPropertyKeywords.hasOwnProperty(word)) - override = "string-2"; - else if (valueKeywords.hasOwnProperty(word)) - override = "atom"; - else if (colorKeywords.hasOwnProperty(word)) - override = "keyword"; - else - override = "error"; - } - return state.context.type; - }; - - states.atComponentBlock = function(type, stream, state) { - if (type == "}") - return popAndPass(type, stream, state); - if (type == "{") - return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); - if (type == "word") - override = "error"; - return state.context.type; - }; - - states.atBlock_parens = function(type, stream, state) { - if (type == ")") return popContext(state); - if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); - return states.atBlock(type, stream, state); - }; - - states.restricted_atBlock_before = function(type, stream, state) { - if (type == "{") - return pushContext(state, stream, "restricted_atBlock"); - if (type == "word" && state.stateArg == "@counter-style") { - override = "variable"; - return "restricted_atBlock_before"; - } - return pass(type, stream, state); - }; - - states.restricted_atBlock = function(type, stream, state) { - if (type == "}") { - state.stateArg = null; - return popContext(state); - } - if (type == "word") { - if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || - (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) - override = "error"; - else - override = "property"; - return "maybeprop"; - } - return "restricted_atBlock"; - }; - - states.keyframes = function(type, stream, state) { - if (type == "word") { override = "variable"; return "keyframes"; } - if (type == "{") return pushContext(state, stream, "top"); - return pass(type, stream, state); - }; - - states.at = function(type, stream, state) { - if (type == ";") return popContext(state); - if (type == "{" || type == "}") return popAndPass(type, stream, state); - if (type == "word") override = "tag"; - else if (type == "hash") override = "builtin"; - return "at"; - }; - - states.interpolation = function(type, stream, state) { - if (type == "}") return popContext(state); - if (type == "{" || type == ";") return popAndPass(type, stream, state); - if (type == "word") override = "variable"; - else if (type != "variable" && type != "(" && type != ")") override = "error"; - return "interpolation"; - }; - - return { - startState: function(base) { - return {tokenize: null, - state: inline ? "block" : "top", - stateArg: null, - context: new Context(inline ? "block" : "top", base || 0, null)}; - }, - - token: function(stream, state) { - if (!state.tokenize && stream.eatSpace()) return null; - var style = (state.tokenize || tokenBase)(stream, state); - if (style && typeof style == "object") { - type = style[1]; - style = style[0]; - } - override = style; - if (type != "comment") - state.state = states[state.state](type, stream, state); - return override; - }, - - indent: function(state, textAfter) { - var cx = state.context, ch = textAfter && textAfter.charAt(0); - var indent = cx.indent; - if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; - if (cx.prev) { - if (ch == "}" && (cx.type == "block" || cx.type == "top" || - cx.type == "interpolation" || cx.type == "restricted_atBlock")) { - // Resume indentation from parent context. - cx = cx.prev; - indent = cx.indent; - } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || - ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { - // Dedent relative to current context. - indent = Math.max(0, cx.indent - indentUnit); - } - } - return indent; - }, - - electricChars: "}", - blockCommentStart: "/*", - blockCommentEnd: "*/", - blockCommentContinue: " * ", - lineComment: lineComment, - fold: "brace" - }; - }); - - function keySet(array) { - var keys = {}; - for (var i = 0; i < array.length; ++i) { - keys[array[i].toLowerCase()] = true; - } - return keys; - } - - var documentTypes_ = [ - "domain", "regexp", "url", "url-prefix" - ], documentTypes = keySet(documentTypes_); - - var mediaTypes_ = [ - "all", "aural", "braille", "handheld", "print", "projection", "screen", - "tty", "tv", "embossed" - ], mediaTypes = keySet(mediaTypes_); - - var mediaFeatures_ = [ - "width", "min-width", "max-width", "height", "min-height", "max-height", - "device-width", "min-device-width", "max-device-width", "device-height", - "min-device-height", "max-device-height", "aspect-ratio", - "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", - "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", - "max-color", "color-index", "min-color-index", "max-color-index", - "monochrome", "min-monochrome", "max-monochrome", "resolution", - "min-resolution", "max-resolution", "scan", "grid", "orientation", - "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", - "pointer", "any-pointer", "hover", "any-hover" - ], mediaFeatures = keySet(mediaFeatures_); - - var mediaValueKeywords_ = [ - "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", - "interlace", "progressive" - ], mediaValueKeywords = keySet(mediaValueKeywords_); - - var propertyKeywords_ = [ - "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "anchor-point", "animation", "animation-delay", - "animation-direction", "animation-duration", "animation-fill-mode", - "animation-iteration-count", "animation-name", "animation-play-state", - "animation-timing-function", "appearance", "azimuth", "backface-visibility", - "background", "background-attachment", "background-blend-mode", "background-clip", - "background-color", "background-image", "background-origin", "background-position", - "background-repeat", "background-size", "baseline-shift", "binding", - "bleed", "bookmark-label", "bookmark-level", "bookmark-state", - "bookmark-target", "border", "border-bottom", "border-bottom-color", - "border-bottom-left-radius", "border-bottom-right-radius", - "border-bottom-style", "border-bottom-width", "border-collapse", - "border-color", "border-image", "border-image-outset", - "border-image-repeat", "border-image-slice", "border-image-source", - "border-image-width", "border-left", "border-left-color", - "border-left-style", "border-left-width", "border-radius", "border-right", - "border-right-color", "border-right-style", "border-right-width", - "border-spacing", "border-style", "border-top", "border-top-color", - "border-top-left-radius", "border-top-right-radius", "border-top-style", - "border-top-width", "border-width", "bottom", "box-decoration-break", - "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", - "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count", - "column-fill", "column-gap", "column-rule", "column-rule-color", - "column-rule-style", "column-rule-width", "column-span", "column-width", - "columns", "content", "counter-increment", "counter-reset", "crop", "cue", - "cue-after", "cue-before", "cursor", "direction", "display", - "dominant-baseline", "drop-initial-after-adjust", - "drop-initial-after-align", "drop-initial-before-adjust", - "drop-initial-before-align", "drop-initial-size", "drop-initial-value", - "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", - "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", - "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", - "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", - "font-stretch", "font-style", "font-synthesis", "font-variant", - "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", - "font-variant-ligatures", "font-variant-numeric", "font-variant-position", - "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", - "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap", - "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", - "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", - "grid-template-rows", "hanging-punctuation", "height", "hyphens", - "icon", "image-orientation", "image-rendering", "image-resolution", - "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing", - "line-break", "line-height", "line-stacking", "line-stacking-ruby", - "line-stacking-shift", "line-stacking-strategy", "list-style", - "list-style-image", "list-style-position", "list-style-type", "margin", - "margin-bottom", "margin-left", "margin-right", "margin-top", - "marks", "marquee-direction", "marquee-loop", - "marquee-play-count", "marquee-speed", "marquee-style", "max-height", - "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", - "nav-left", "nav-right", "nav-up", "object-fit", "object-position", - "opacity", "order", "orphans", "outline", - "outline-color", "outline-offset", "outline-style", "outline-width", - "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", - "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", - "page", "page-break-after", "page-break-before", "page-break-inside", - "page-policy", "pause", "pause-after", "pause-before", "perspective", - "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position", - "presentation-level", "punctuation-trim", "quotes", "region-break-after", - "region-break-before", "region-break-inside", "region-fragment", - "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", - "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", - "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", - "shape-outside", "size", "speak", "speak-as", "speak-header", - "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", - "tab-size", "table-layout", "target", "target-name", "target-new", - "target-position", "text-align", "text-align-last", "text-decoration", - "text-decoration-color", "text-decoration-line", "text-decoration-skip", - "text-decoration-style", "text-emphasis", "text-emphasis-color", - "text-emphasis-position", "text-emphasis-style", "text-height", - "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", - "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", - "text-wrap", "top", "transform", "transform-origin", "transform-style", - "transition", "transition-delay", "transition-duration", - "transition-property", "transition-timing-function", "unicode-bidi", - "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", - "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", - "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break", - "word-spacing", "word-wrap", "z-index", - // SVG-specific - "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", - "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", - "color-interpolation", "color-interpolation-filters", - "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", - "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", - "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", - "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", - "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", - "glyph-orientation-vertical", "text-anchor", "writing-mode" - ], propertyKeywords = keySet(propertyKeywords_); - - var nonStandardPropertyKeywords_ = [ - "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", - "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", - "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", - "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", - "searchfield-results-decoration", "zoom" - ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); - - var fontProperties_ = [ - "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", - "font-stretch", "font-weight", "font-style" - ], fontProperties = keySet(fontProperties_); - - var counterDescriptors_ = [ - "additive-symbols", "fallback", "negative", "pad", "prefix", "range", - "speak-as", "suffix", "symbols", "system" - ], counterDescriptors = keySet(counterDescriptors_); - - var colorKeywords_ = [ - "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", - "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", - "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", - "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", - "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", - "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", - "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", - "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", - "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", - "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", - "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", - "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", - "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", - "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", - "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", - "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", - "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", - "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", - "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", - "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", - "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", - "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", - "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", - "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", - "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", - "whitesmoke", "yellow", "yellowgreen" - ], colorKeywords = keySet(colorKeywords_); - - var valueKeywords_ = [ - "above", "absolute", "activeborder", "additive", "activecaption", "afar", - "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", - "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", - "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", - "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", - "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", - "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", - "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", - "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", - "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", - "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", - "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", - "compact", "condensed", "contain", "content", "contents", - "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", - "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", - "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", - "destination-in", "destination-out", "destination-over", "devanagari", "difference", - "disc", "discard", "disclosure-closed", "disclosure-open", "document", - "dot-dash", "dot-dot-dash", - "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", - "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", - "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", - "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", - "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", - "ethiopic-halehame-gez", "ethiopic-halehame-om-et", - "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", - "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", - "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", - "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", - "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", - "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", - "help", "hidden", "hide", "higher", "highlight", "highlighttext", - "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", - "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", - "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", - "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", - "italic", "japanese-formal", "japanese-informal", "justify", "kannada", - "katakana", "katakana-iroha", "keep-all", "khmer", - "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", - "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", - "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", - "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", - "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", - "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", - "media-controls-background", "media-current-time-display", - "media-fullscreen-button", "media-mute-button", "media-play-button", - "media-return-to-realtime-button", "media-rewind-button", - "media-seek-back-button", "media-seek-forward-button", "media-slider", - "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", - "media-volume-slider-container", "media-volume-sliderthumb", "medium", - "menu", "menulist", "menulist-button", "menulist-text", - "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", - "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", - "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", - "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", - "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", - "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", - "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", - "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", - "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", - "progress", "push-button", "radial-gradient", "radio", "read-only", - "read-write", "read-write-plaintext-only", "rectangle", "region", - "relative", "repeat", "repeating-linear-gradient", - "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", - "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", - "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", - "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", - "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", - "searchfield-cancel-button", "searchfield-decoration", - "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", - "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", - "simp-chinese-formal", "simp-chinese-informal", "single", - "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", - "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", - "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", - "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", - "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", - "table-caption", "table-cell", "table-column", "table-column-group", - "table-footer-group", "table-header-group", "table-row", "table-row-group", - "tamil", - "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", - "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", - "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", - "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", - "trad-chinese-formal", "trad-chinese-informal", "transform", - "translate", "translate3d", "translateX", "translateY", "translateZ", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", - "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", - "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", - "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", - "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", - "xx-large", "xx-small" - ], valueKeywords = keySet(valueKeywords_); - - var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) - .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) - .concat(valueKeywords_); - CodeMirror.registerHelper("hintWords", "css", allWords); - - function tokenCComment(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (maybeEnd && ch == "/") { - state.tokenize = null; - break; - } - maybeEnd = (ch == "*"); - } - return ["comment", "comment"]; - } - - CodeMirror.defineMIME("text/css", { - documentTypes: documentTypes, - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - fontProperties: fontProperties, - counterDescriptors: counterDescriptors, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - tokenHooks: { - "/": function(stream, state) { - if (!stream.eat("*")) return false; - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } - }, - name: "css" - }); - - CodeMirror.defineMIME("text/x-scss", { - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - fontProperties: fontProperties, - allowNested: true, - lineComment: "//", - tokenHooks: { - "/": function(stream, state) { - if (stream.eat("/")) { - stream.skipToEnd(); - return ["comment", "comment"]; - } else if (stream.eat("*")) { - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } else { - return ["operator", "operator"]; - } - }, - ":": function(stream) { - if (stream.match(/\s*\{/, false)) - return [null, null] - return false; - }, - "$": function(stream) { - stream.match(/^[\w-]+/); - if (stream.match(/^\s*:/, false)) - return ["variable-2", "variable-definition"]; - return ["variable-2", "variable"]; - }, - "#": function(stream) { - if (!stream.eat("{")) return false; - return [null, "interpolation"]; - } - }, - name: "css", - helperType: "scss" - }); - - CodeMirror.defineMIME("text/x-less", { - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - mediaValueKeywords: mediaValueKeywords, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - fontProperties: fontProperties, - allowNested: true, - lineComment: "//", - tokenHooks: { - "/": function(stream, state) { - if (stream.eat("/")) { - stream.skipToEnd(); - return ["comment", "comment"]; - } else if (stream.eat("*")) { - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } else { - return ["operator", "operator"]; - } - }, - "@": function(stream) { - if (stream.eat("{")) return [null, "interpolation"]; - if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; - stream.eatWhile(/[\w\\\-]/); - if (stream.match(/^\s*:/, false)) - return ["variable-2", "variable-definition"]; - return ["variable-2", "variable"]; - }, - "&": function() { - return ["atom", "atom"]; - } - }, - name: "css", - helperType: "less" - }); - - CodeMirror.defineMIME("text/x-gss", { - documentTypes: documentTypes, - mediaTypes: mediaTypes, - mediaFeatures: mediaFeatures, - propertyKeywords: propertyKeywords, - nonStandardPropertyKeywords: nonStandardPropertyKeywords, - fontProperties: fontProperties, - counterDescriptors: counterDescriptors, - colorKeywords: colorKeywords, - valueKeywords: valueKeywords, - supportsAtComponent: true, - tokenHooks: { - "/": function(stream, state) { - if (!stream.eat("*")) return false; - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } - }, - name: "css", - helperType: "gss" - }); - - }); - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(9), __webpack_require__(8), __webpack_require__(10)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var defaultTags = { - script: [ - ["lang", /(javascript|babel)/i, "javascript"], - ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"], - ["type", /./, "text/plain"], - [null, null, "javascript"] - ], - style: [ - ["lang", /^css$/i, "css"], - ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], - ["type", /./, "text/plain"], - [null, null, "css"] - ] - }; - - function maybeBackup(stream, pat, style) { - var cur = stream.current(), close = cur.search(pat); - if (close > -1) { - stream.backUp(cur.length - close); - } else if (cur.match(/<\/?$/)) { - stream.backUp(cur.length); - if (!stream.match(pat, false)) stream.match(cur); - } - return style; - } - - var attrRegexpCache = {}; - function getAttrRegexp(attr) { - var regexp = attrRegexpCache[attr]; - if (regexp) return regexp; - return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); - } - - function getAttrValue(text, attr) { - var match = text.match(getAttrRegexp(attr)) - return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" - } - - function getTagRegexp(tagName, anchored) { - return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); - } - - function addTags(from, to) { - for (var tag in from) { - var dest = to[tag] || (to[tag] = []); - var source = from[tag]; - for (var i = source.length - 1; i >= 0; i--) - dest.unshift(source[i]) - } - } - - function findMatchingMode(tagInfo, tagText) { - for (var i = 0; i < tagInfo.length; i++) { - var spec = tagInfo[i]; - if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; - } - } - - CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { - var htmlMode = CodeMirror.getMode(config, { - name: "xml", - htmlMode: true, - multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, - multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag - }); - - var tags = {}; - var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; - addTags(defaultTags, tags); - if (configTags) addTags(configTags, tags); - if (configScript) for (var i = configScript.length - 1; i >= 0; i--) - tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) - - function html(stream, state) { - var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName - if (tag && !/[<>\s\/]/.test(stream.current()) && - (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && - tags.hasOwnProperty(tagName)) { - state.inTag = tagName + " " - } else if (state.inTag && tag && />$/.test(stream.current())) { - var inTag = /^([\S]+) (.*)/.exec(state.inTag) - state.inTag = null - var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) - var mode = CodeMirror.getMode(config, modeSpec) - var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); - state.token = function (stream, state) { - if (stream.match(endTagA, false)) { - state.token = html; - state.localState = state.localMode = null; - return null; - } - return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); - }; - state.localMode = mode; - state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); - } else if (state.inTag) { - state.inTag += stream.current() - if (stream.eol()) state.inTag += " " - } - return style; - }; - - return { - startState: function () { - var state = CodeMirror.startState(htmlMode); - return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; - }, - - copyState: function (state) { - var local; - if (state.localState) { - local = CodeMirror.copyState(state.localMode, state.localState); - } - return {token: state.token, inTag: state.inTag, - localMode: state.localMode, localState: local, - htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; - }, - - token: function (stream, state) { - return state.token(stream, state); - }, - - indent: function (state, textAfter, line) { - if (!state.localMode || /^\s*<\//.test(textAfter)) - return htmlMode.indent(state.htmlState, textAfter); - else if (state.localMode.indent) - return state.localMode.indent(state.localState, textAfter, line); - else - return CodeMirror.Pass; - }, - - innerMode: function (state) { - return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; - } - }; - }, "xml", "javascript", "css"); - - CodeMirror.defineMIME("text/html", "htmlmixed"); - }); - - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(9), __webpack_require__(8)) - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript"], mod) - else // Plain browser env - mod(CodeMirror) - })(function(CodeMirror) { - "use strict" - - // Depth means the amount of open braces in JS context, in XML - // context 0 means not in tag, 1 means in tag, and 2 means in tag - // and js block comment. - function Context(state, mode, depth, prev) { - this.state = state; this.mode = mode; this.depth = depth; this.prev = prev - } - - function copyContext(context) { - return new Context(CodeMirror.copyState(context.mode, context.state), - context.mode, - context.depth, - context.prev && copyContext(context.prev)) - } - - CodeMirror.defineMode("jsx", function(config, modeConfig) { - var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true}) - var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript") - - function flatXMLIndent(state) { - var tagName = state.tagName - state.tagName = null - var result = xmlMode.indent(state, "") - state.tagName = tagName - return result - } - - function token(stream, state) { - if (state.context.mode == xmlMode) - return xmlToken(stream, state, state.context) - else - return jsToken(stream, state, state.context) - } - - function xmlToken(stream, state, cx) { - if (cx.depth == 2) { // Inside a JS /* */ comment - if (stream.match(/^.*?\*\//)) cx.depth = 1 - else stream.skipToEnd() - return "comment" - } - - if (stream.peek() == "{") { - xmlMode.skipAttribute(cx.state) - - var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context - // If JS starts on same line as tag - if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) { - while (xmlContext.prev && !xmlContext.startOfLine) - xmlContext = xmlContext.prev - // If tag starts the line, use XML indentation level - if (xmlContext.startOfLine) indent -= config.indentUnit - // Else use JS indentation level - else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented - // Else if inside of tag - } else if (cx.depth == 1) { - indent += config.indentUnit - } - - state.context = new Context(CodeMirror.startState(jsMode, indent), - jsMode, 0, state.context) - return null - } - - if (cx.depth == 1) { // Inside of tag - if (stream.peek() == "<") { // Tag inside of tag - xmlMode.skipAttribute(cx.state) - state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)), - xmlMode, 0, state.context) - return null - } else if (stream.match("//")) { - stream.skipToEnd() - return "comment" - } else if (stream.match("/*")) { - cx.depth = 2 - return token(stream, state) - } - } - - var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop - if (/\btag\b/.test(style)) { - if (/>$/.test(cur)) { - if (cx.state.context) cx.depth = 0 - else state.context = state.context.prev - } else if (/^ -1) { - stream.backUp(cur.length - stop) - } - return style - } - - function jsToken(stream, state, cx) { - if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) { - jsMode.skipExpression(cx.state) - state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")), - xmlMode, 0, state.context) - return null - } - - var style = jsMode.token(stream, cx.state) - if (!style && cx.depth != null) { - var cur = stream.current() - if (cur == "{") { - cx.depth++ - } else if (cur == "}") { - if (--cx.depth == 0) state.context = state.context.prev - } - } - return style - } - - return { - startState: function() { - return {context: new Context(CodeMirror.startState(jsMode), jsMode)} - }, - - copyState: function(state) { - return {context: copyContext(state.context)} - }, - - token: token, - - indent: function(state, textAfter, fullLine) { - return state.context.mode.indent(state.context.state, textAfter, fullLine) - }, - - innerMode: function(state) { - return state.context - } - } - }, "xml", "javascript") - - CodeMirror.defineMIME("text/jsx", "jsx") - CodeMirror.defineMIME("text/typescript-jsx", {name: "jsx", base: {name: "javascript", typescript: true}}) - }); - - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - /** - * Link to the project's GitHub page: - * https://github.com/pickhardt/coffeescript-codemirror-mode - */ - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.defineMode("coffeescript", function(conf, parserConf) { - var ERRORCLASS = "error"; - - function wordRegexp(words) { - return new RegExp("^((" + words.join(")|(") + "))\\b"); - } - - var operators = /^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/; - var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/; - var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/; - var atProp = /^@[_A-Za-z$][_A-Za-z$0-9]*/; - - var wordOperators = wordRegexp(["and", "or", "not", - "is", "isnt", "in", - "instanceof", "typeof"]); - var indentKeywords = ["for", "while", "loop", "if", "unless", "else", - "switch", "try", "catch", "finally", "class"]; - var commonKeywords = ["break", "by", "continue", "debugger", "delete", - "do", "in", "of", "new", "return", "then", - "this", "@", "throw", "when", "until", "extends"]; - - var keywords = wordRegexp(indentKeywords.concat(commonKeywords)); - - indentKeywords = wordRegexp(indentKeywords); - - - var stringPrefixes = /^('{3}|\"{3}|['\"])/; - var regexPrefixes = /^(\/{3}|\/)/; - var commonConstants = ["Infinity", "NaN", "undefined", "null", "true", "false", "on", "off", "yes", "no"]; - var constants = wordRegexp(commonConstants); - - // Tokenizers - function tokenBase(stream, state) { - // Handle scope changes - if (stream.sol()) { - if (state.scope.align === null) state.scope.align = false; - var scopeOffset = state.scope.offset; - if (stream.eatSpace()) { - var lineOffset = stream.indentation(); - if (lineOffset > scopeOffset && state.scope.type == "coffee") { - return "indent"; - } else if (lineOffset < scopeOffset) { - return "dedent"; - } - return null; - } else { - if (scopeOffset > 0) { - dedent(stream, state); - } - } - } - if (stream.eatSpace()) { - return null; - } - - var ch = stream.peek(); - - // Handle docco title comment (single line) - if (stream.match("####")) { - stream.skipToEnd(); - return "comment"; - } - - // Handle multi line comments - if (stream.match("###")) { - state.tokenize = longComment; - return state.tokenize(stream, state); - } - - // Single line comment - if (ch === "#") { - stream.skipToEnd(); - return "comment"; - } - - // Handle number literals - if (stream.match(/^-?[0-9\.]/, false)) { - var floatLiteral = false; - // Floats - if (stream.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)) { - floatLiteral = true; - } - if (stream.match(/^-?\d+\.\d*/)) { - floatLiteral = true; - } - if (stream.match(/^-?\.\d+/)) { - floatLiteral = true; - } - - if (floatLiteral) { - // prevent from getting extra . on 1.. - if (stream.peek() == "."){ - stream.backUp(1); - } - return "number"; - } - // Integers - var intLiteral = false; - // Hex - if (stream.match(/^-?0x[0-9a-f]+/i)) { - intLiteral = true; - } - // Decimal - if (stream.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)) { - intLiteral = true; - } - // Zero by itself with no other piece of number. - if (stream.match(/^-?0(?![\dx])/i)) { - intLiteral = true; - } - if (intLiteral) { - return "number"; - } - } - - // Handle strings - if (stream.match(stringPrefixes)) { - state.tokenize = tokenFactory(stream.current(), false, "string"); - return state.tokenize(stream, state); - } - // Handle regex literals - if (stream.match(regexPrefixes)) { - if (stream.current() != "/" || stream.match(/^.*\//, false)) { // prevent highlight of division - state.tokenize = tokenFactory(stream.current(), true, "string-2"); - return state.tokenize(stream, state); - } else { - stream.backUp(1); - } - } - - - - // Handle operators and delimiters - if (stream.match(operators) || stream.match(wordOperators)) { - return "operator"; - } - if (stream.match(delimiters)) { - return "punctuation"; - } - - if (stream.match(constants)) { - return "atom"; - } - - if (stream.match(atProp) || state.prop && stream.match(identifiers)) { - return "property"; - } - - if (stream.match(keywords)) { - return "keyword"; - } - - if (stream.match(identifiers)) { - return "variable"; - } - - // Handle non-detected items - stream.next(); - return ERRORCLASS; - } - - function tokenFactory(delimiter, singleline, outclass) { - return function(stream, state) { - while (!stream.eol()) { - stream.eatWhile(/[^'"\/\\]/); - if (stream.eat("\\")) { - stream.next(); - if (singleline && stream.eol()) { - return outclass; - } - } else if (stream.match(delimiter)) { - state.tokenize = tokenBase; - return outclass; - } else { - stream.eat(/['"\/]/); - } - } - if (singleline) { - if (parserConf.singleLineStringErrors) { - outclass = ERRORCLASS; - } else { - state.tokenize = tokenBase; - } - } - return outclass; - }; - } - - function longComment(stream, state) { - while (!stream.eol()) { - stream.eatWhile(/[^#]/); - if (stream.match("###")) { - state.tokenize = tokenBase; - break; - } - stream.eatWhile("#"); - } - return "comment"; - } - - function indent(stream, state, type) { - type = type || "coffee"; - var offset = 0, align = false, alignOffset = null; - for (var scope = state.scope; scope; scope = scope.prev) { - if (scope.type === "coffee" || scope.type == "}") { - offset = scope.offset + conf.indentUnit; - break; - } - } - if (type !== "coffee") { - align = null; - alignOffset = stream.column() + stream.current().length; - } else if (state.scope.align) { - state.scope.align = false; - } - state.scope = { - offset: offset, - type: type, - prev: state.scope, - align: align, - alignOffset: alignOffset - }; - } - - function dedent(stream, state) { - if (!state.scope.prev) return; - if (state.scope.type === "coffee") { - var _indent = stream.indentation(); - var matched = false; - for (var scope = state.scope; scope; scope = scope.prev) { - if (_indent === scope.offset) { - matched = true; - break; - } - } - if (!matched) { - return true; - } - while (state.scope.prev && state.scope.offset !== _indent) { - state.scope = state.scope.prev; - } - return false; - } else { - state.scope = state.scope.prev; - return false; - } - } - - function tokenLexer(stream, state) { - var style = state.tokenize(stream, state); - var current = stream.current(); - - // Handle scope changes. - if (current === "return") { - state.dedent = true; - } - if (((current === "->" || current === "=>") && stream.eol()) - || style === "indent") { - indent(stream, state); - } - var delimiter_index = "[({".indexOf(current); - if (delimiter_index !== -1) { - indent(stream, state, "])}".slice(delimiter_index, delimiter_index+1)); - } - if (indentKeywords.exec(current)){ - indent(stream, state); - } - if (current == "then"){ - dedent(stream, state); - } - - - if (style === "dedent") { - if (dedent(stream, state)) { - return ERRORCLASS; - } - } - delimiter_index = "])}".indexOf(current); - if (delimiter_index !== -1) { - while (state.scope.type == "coffee" && state.scope.prev) - state.scope = state.scope.prev; - if (state.scope.type == current) - state.scope = state.scope.prev; - } - if (state.dedent && stream.eol()) { - if (state.scope.type == "coffee" && state.scope.prev) - state.scope = state.scope.prev; - state.dedent = false; - } - - return style; - } - - var external = { - startState: function(basecolumn) { - return { - tokenize: tokenBase, - scope: {offset:basecolumn || 0, type:"coffee", prev: null, align: false}, - prop: false, - dedent: 0 - }; - }, - - token: function(stream, state) { - var fillAlign = state.scope.align === null && state.scope; - if (fillAlign && stream.sol()) fillAlign.align = false; - - var style = tokenLexer(stream, state); - if (style && style != "comment") { - if (fillAlign) fillAlign.align = true; - state.prop = style == "punctuation" && stream.current() == "." - } - - return style; - }, - - indent: function(state, text) { - if (state.tokenize != tokenBase) return 0; - var scope = state.scope; - var closer = text && "])}".indexOf(text.charAt(0)) > -1; - if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev; - var closes = closer && scope.type === text.charAt(0); - if (scope.align) - return scope.alignOffset - (closes ? 1 : 0); - else - return (closes ? scope.prev : scope).offset; - }, - - lineComment: "#", - fold: "indent" - }; - return external; - }); - - // IANA registered media type - // https://www.iana.org/assignments/media-types/ - CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript"); - - CodeMirror.defineMIME("text/x-coffeescript", "coffeescript"); - CodeMirror.defineMIME("text/coffeescript", "coffeescript"); - - }); - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.defineMode("elm", function() { - - function switchState(source, setState, f) { - setState(f); - return f(source, setState); - } - - // These should all be Unicode extended, as per the Haskell 2010 report - var smallRE = /[a-z_]/; - var largeRE = /[A-Z]/; - var digitRE = /[0-9]/; - var hexitRE = /[0-9A-Fa-f]/; - var octitRE = /[0-7]/; - var idRE = /[a-z_A-Z0-9\']/; - var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:\u03BB\u2192]/; - var specialRE = /[(),;[\]`{}]/; - var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer - - function normal() { - return function (source, setState) { - if (source.eatWhile(whiteCharRE)) { - return null; - } - - var ch = source.next(); - if (specialRE.test(ch)) { - if (ch == '{' && source.eat('-')) { - var t = "comment"; - if (source.eat('#')) t = "meta"; - return switchState(source, setState, ncomment(t, 1)); - } - return null; - } - - if (ch == '\'') { - if (source.eat('\\')) - source.next(); // should handle other escapes here - else - source.next(); - - if (source.eat('\'')) - return "string"; - return "error"; - } - - if (ch == '"') { - return switchState(source, setState, stringLiteral); - } - - if (largeRE.test(ch)) { - source.eatWhile(idRE); - if (source.eat('.')) - return "qualifier"; - return "variable-2"; - } - - if (smallRE.test(ch)) { - var isDef = source.pos === 1; - source.eatWhile(idRE); - return isDef ? "type" : "variable"; - } - - if (digitRE.test(ch)) { - if (ch == '0') { - if (source.eat(/[xX]/)) { - source.eatWhile(hexitRE); // should require at least 1 - return "integer"; - } - if (source.eat(/[oO]/)) { - source.eatWhile(octitRE); // should require at least 1 - return "number"; - } - } - source.eatWhile(digitRE); - var t = "number"; - if (source.eat('.')) { - t = "number"; - source.eatWhile(digitRE); // should require at least 1 - } - if (source.eat(/[eE]/)) { - t = "number"; - source.eat(/[-+]/); - source.eatWhile(digitRE); // should require at least 1 - } - return t; - } - - if (symbolRE.test(ch)) { - if (ch == '-' && source.eat(/-/)) { - source.eatWhile(/-/); - if (!source.eat(symbolRE)) { - source.skipToEnd(); - return "comment"; - } - } - source.eatWhile(symbolRE); - return "builtin"; - } - - return "error"; - } - } - - function ncomment(type, nest) { - if (nest == 0) { - return normal(); - } - return function(source, setState) { - var currNest = nest; - while (!source.eol()) { - var ch = source.next(); - if (ch == '{' && source.eat('-')) { - ++currNest; - } else if (ch == '-' && source.eat('}')) { - --currNest; - if (currNest == 0) { - setState(normal()); - return type; - } - } - } - setState(ncomment(type, currNest)); - return type; - } - } - - function stringLiteral(source, setState) { - while (!source.eol()) { - var ch = source.next(); - if (ch == '"') { - setState(normal()); - return "string"; - } - if (ch == '\\') { - if (source.eol() || source.eat(whiteCharRE)) { - setState(stringGap); - return "string"; - } - if (!source.eat('&')) source.next(); // should handle other escapes here - } - } - setState(normal()); - return "error"; - } - - function stringGap(source, setState) { - if (source.eat('\\')) { - return switchState(source, setState, stringLiteral); - } - source.next(); - setState(normal()); - return "error"; - } - - - var wellKnownWords = (function() { - var wkw = {}; - - var keywords = [ - "case", "of", "as", - "if", "then", "else", - "let", "in", - "infix", "infixl", "infixr", - "type", "alias", - "input", "output", "foreign", "loopback", - "module", "where", "import", "exposing", - "_", "..", "|", ":", "=", "\\", "\"", "->", "<-" - ]; - - for (var i = keywords.length; i--;) - wkw[keywords[i]] = "keyword"; - - return wkw; - })(); - - - - return { - startState: function () { return { f: normal() }; }, - copyState: function (s) { return { f: s.f }; }, - - token: function(stream, state) { - var t = state.f(stream, function(s) { state.f = s; }); - var w = stream.current(); - return (wellKnownWords.hasOwnProperty(w)) ? wellKnownWords[w] : t; - } - }; - - }); - - CodeMirror.defineMIME("text/x-elm", "elm"); - }); - - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - function Context(indented, column, type, info, align, prev) { - this.indented = indented; - this.column = column; - this.type = type; - this.info = info; - this.align = align; - this.prev = prev; - } - function pushContext(state, col, type, info) { - var indent = state.indented; - if (state.context && state.context.type == "statement" && type != "statement") - indent = state.context.indented; - return state.context = new Context(indent, col, type, info, null, state.context); - } - function popContext(state) { - var t = state.context.type; - if (t == ")" || t == "]" || t == "}") - state.indented = state.context.indented; - return state.context = state.context.prev; - } - - function typeBefore(stream, state, pos) { - if (state.prevToken == "variable" || state.prevToken == "type") return true; - if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true; - if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; - } - - function isTopScope(context) { - for (;;) { - if (!context || context.type == "top") return true; - if (context.type == "}" && context.prev.info != "namespace") return false; - context = context.prev; - } - } - - CodeMirror.defineMode("clike", function(config, parserConfig) { - var indentUnit = config.indentUnit, - statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, - dontAlignCalls = parserConfig.dontAlignCalls, - keywords = parserConfig.keywords || {}, - types = parserConfig.types || {}, - builtin = parserConfig.builtin || {}, - blockKeywords = parserConfig.blockKeywords || {}, - defKeywords = parserConfig.defKeywords || {}, - atoms = parserConfig.atoms || {}, - hooks = parserConfig.hooks || {}, - multiLineStrings = parserConfig.multiLineStrings, - indentStatements = parserConfig.indentStatements !== false, - indentSwitch = parserConfig.indentSwitch !== false, - namespaceSeparator = parserConfig.namespaceSeparator, - isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, - numberStart = parserConfig.numberStart || /[\d\.]/, - number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, - isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/, - isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/; - - var curPunc, isDefKeyword; - - function tokenBase(stream, state) { - var ch = stream.next(); - if (hooks[ch]) { - var result = hooks[ch](stream, state); - if (result !== false) return result; - } - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } - if (isPunctuationChar.test(ch)) { - curPunc = ch; - return null; - } - if (numberStart.test(ch)) { - stream.backUp(1) - if (stream.match(number)) return "number" - stream.next() - } - if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } - if (stream.eat("/")) { - stream.skipToEnd(); - return "comment"; - } - } - if (isOperatorChar.test(ch)) { - while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} - return "operator"; - } - stream.eatWhile(isIdentifierChar); - if (namespaceSeparator) while (stream.match(namespaceSeparator)) - stream.eatWhile(isIdentifierChar); - - var cur = stream.current(); - if (contains(keywords, cur)) { - if (contains(blockKeywords, cur)) curPunc = "newstatement"; - if (contains(defKeywords, cur)) isDefKeyword = true; - return "keyword"; - } - if (contains(types, cur)) return "type"; - if (contains(builtin, cur)) { - if (contains(blockKeywords, cur)) curPunc = "newstatement"; - return "builtin"; - } - if (contains(atoms, cur)) return "atom"; - return "variable"; - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) {end = true; break;} - escaped = !escaped && next == "\\"; - } - if (end || !(escaped || multiLineStrings)) - state.tokenize = null; - return "string"; - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = null; - break; - } - maybeEnd = (ch == "*"); - } - return "comment"; - } - - function maybeEOL(stream, state) { - if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) - state.typeAtEndOfLine = typeBefore(stream, state, stream.pos) - } - - // Interface - - return { - startState: function(basecolumn) { - return { - tokenize: null, - context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), - indented: 0, - startOfLine: true, - prevToken: null - }; - }, - - token: function(stream, state) { - var ctx = state.context; - if (stream.sol()) { - if (ctx.align == null) ctx.align = false; - state.indented = stream.indentation(); - state.startOfLine = true; - } - if (stream.eatSpace()) { maybeEOL(stream, state); return null; } - curPunc = isDefKeyword = null; - var style = (state.tokenize || tokenBase)(stream, state); - if (style == "comment" || style == "meta") return style; - if (ctx.align == null) ctx.align = true; - - if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) - while (state.context.type == "statement") popContext(state); - else if (curPunc == "{") pushContext(state, stream.column(), "}"); - else if (curPunc == "[") pushContext(state, stream.column(), "]"); - else if (curPunc == "(") pushContext(state, stream.column(), ")"); - else if (curPunc == "}") { - while (ctx.type == "statement") ctx = popContext(state); - if (ctx.type == "}") ctx = popContext(state); - while (ctx.type == "statement") ctx = popContext(state); - } - else if (curPunc == ctx.type) popContext(state); - else if (indentStatements && - (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || - (ctx.type == "statement" && curPunc == "newstatement"))) { - pushContext(state, stream.column(), "statement", stream.current()); - } - - if (style == "variable" && - ((state.prevToken == "def" || - (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && - isTopScope(state.context) && stream.match(/^\s*\(/, false))))) - style = "def"; - - if (hooks.token) { - var result = hooks.token(stream, state, style); - if (result !== undefined) style = result; - } - - if (style == "def" && parserConfig.styleDefs === false) style = "variable"; - - state.startOfLine = false; - state.prevToken = isDefKeyword ? "def" : style || curPunc; - maybeEOL(stream, state); - return style; - }, - - indent: function(state, textAfter) { - if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; - var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); - if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; - if (parserConfig.dontIndentStatements) - while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) - ctx = ctx.prev - if (hooks.indent) { - var hook = hooks.indent(state, ctx, textAfter); - if (typeof hook == "number") return hook - } - var closing = firstChar == ctx.type; - var switchBlock = ctx.prev && ctx.prev.info == "switch"; - if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { - while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev - return ctx.indented - } - if (ctx.type == "statement") - return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); - if (ctx.align && (!dontAlignCalls || ctx.type != ")")) - return ctx.column + (closing ? 0 : 1); - if (ctx.type == ")" && !closing) - return ctx.indented + statementIndentUnit; - - return ctx.indented + (closing ? 0 : indentUnit) + - (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); - }, - - electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, - blockCommentStart: "/*", - blockCommentEnd: "*/", - blockCommentContinue: " * ", - lineComment: "//", - fold: "brace" - }; - }); - - function words(str) { - var obj = {}, words = str.split(" "); - for (var i = 0; i < words.length; ++i) obj[words[i]] = true; - return obj; - } - function contains(words, word) { - if (typeof words === "function") { - return words(word); - } else { - return words.propertyIsEnumerable(word); - } - } - var cKeywords = "auto if break case register continue return default do sizeof " + - "static else struct switch extern typedef union for goto while enum const volatile"; - var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t"; - - function cppHook(stream, state) { - if (!state.startOfLine) return false - for (var ch, next = null; ch = stream.peek();) { - if (ch == "\\" && stream.match(/^.$/)) { - next = cppHook - break - } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { - break - } - stream.next() - } - state.tokenize = next - return "meta" - } - - function pointerHook(_stream, state) { - if (state.prevToken == "type") return "type"; - return false; - } - - function cpp14Literal(stream) { - stream.eatWhile(/[\w\.']/); - return "number"; - } - - function cpp11StringHook(stream, state) { - stream.backUp(1); - // Raw strings. - if (stream.match(/(R|u8R|uR|UR|LR)/)) { - var match = stream.match(/"([^\s\\()]{0,16})\(/); - if (!match) { - return false; - } - state.cpp11RawStringDelim = match[1]; - state.tokenize = tokenRawString; - return tokenRawString(stream, state); - } - // Unicode strings/chars. - if (stream.match(/(u8|u|U|L)/)) { - if (stream.match(/["']/, /* eat */ false)) { - return "string"; - } - return false; - } - // Ignore this hook. - stream.next(); - return false; - } - - function cppLooksLikeConstructor(word) { - var lastTwo = /(\w+)::~?(\w+)$/.exec(word); - return lastTwo && lastTwo[1] == lastTwo[2]; - } - - // C#-style strings where "" escapes a quote. - function tokenAtString(stream, state) { - var next; - while ((next = stream.next()) != null) { - if (next == '"' && !stream.eat('"')) { - state.tokenize = null; - break; - } - } - return "string"; - } - - // C++11 raw string literal is "( anything )", where - // can be a string up to 16 characters long. - function tokenRawString(stream, state) { - // Escape characters that have special regex meanings. - var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); - var match = stream.match(new RegExp(".*?\\)" + delim + '"')); - if (match) - state.tokenize = null; - else - stream.skipToEnd(); - return "string"; - } - - function def(mimes, mode) { - if (typeof mimes == "string") mimes = [mimes]; - var words = []; - function add(obj) { - if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) - words.push(prop); - } - add(mode.keywords); - add(mode.types); - add(mode.builtin); - add(mode.atoms); - if (words.length) { - mode.helperType = mimes[0]; - CodeMirror.registerHelper("hintWords", mimes[0], words); - } - - for (var i = 0; i < mimes.length; ++i) - CodeMirror.defineMIME(mimes[i], mode); - } - - def(["text/x-csrc", "text/x-c", "text/x-chdr"], { - name: "clike", - keywords: words(cKeywords), - types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " + - "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " + - "uint32_t uint64_t"), - blockKeywords: words("case do else for if switch while struct"), - defKeywords: words("struct"), - typeFirstDefinitions: true, - atoms: words("NULL true false"), - hooks: {"#": cppHook, "*": pointerHook}, - modeProps: {fold: ["brace", "include"]} - }); - - def(["text/x-c++src", "text/x-c++hdr"], { - name: "clike", - keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " + - "static_cast typeid catch operator template typename class friend private " + - "this using const_cast inline public throw virtual delete mutable protected " + - "alignas alignof constexpr decltype nullptr noexcept thread_local final " + - "static_assert override"), - types: words(cTypes + " bool wchar_t"), - blockKeywords: words("catch class do else finally for if struct switch try while"), - defKeywords: words("class namespace struct enum union"), - typeFirstDefinitions: true, - atoms: words("true false NULL"), - dontIndentStatements: /^template$/, - isIdentifierChar: /[\w\$_~\xa1-\uffff]/, - hooks: { - "#": cppHook, - "*": pointerHook, - "u": cpp11StringHook, - "U": cpp11StringHook, - "L": cpp11StringHook, - "R": cpp11StringHook, - "0": cpp14Literal, - "1": cpp14Literal, - "2": cpp14Literal, - "3": cpp14Literal, - "4": cpp14Literal, - "5": cpp14Literal, - "6": cpp14Literal, - "7": cpp14Literal, - "8": cpp14Literal, - "9": cpp14Literal, - token: function(stream, state, style) { - if (style == "variable" && stream.peek() == "(" && - (state.prevToken == ";" || state.prevToken == null || - state.prevToken == "}") && - cppLooksLikeConstructor(stream.current())) - return "def"; - } - }, - namespaceSeparator: "::", - modeProps: {fold: ["brace", "include"]} - }); - - def("text/x-java", { - name: "clike", - keywords: words("abstract assert break case catch class const continue default " + - "do else enum extends final finally float for goto if implements import " + - "instanceof interface native new package private protected public " + - "return static strictfp super switch synchronized this throw throws transient " + - "try volatile while @interface"), - types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + - "Integer Long Number Object Short String StringBuffer StringBuilder Void"), - blockKeywords: words("catch class do else finally for if switch try while"), - defKeywords: words("class interface enum @interface"), - typeFirstDefinitions: true, - atoms: words("true false null"), - number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, - hooks: { - "@": function(stream) { - // Don't match the @interface keyword. - if (stream.match('interface', false)) return false; - - stream.eatWhile(/[\w\$_]/); - return "meta"; - } - }, - modeProps: {fold: ["brace", "import"]} - }); - - def("text/x-csharp", { - name: "clike", - keywords: words("abstract as async await base break case catch checked class const continue" + - " default delegate do else enum event explicit extern finally fixed for" + - " foreach goto if implicit in interface internal is lock namespace new" + - " operator out override params private protected public readonly ref return sealed" + - " sizeof stackalloc static struct switch this throw try typeof unchecked" + - " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + - " global group into join let orderby partial remove select set value var yield"), - types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" + - " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" + - " UInt64 bool byte char decimal double short int long object" + - " sbyte float string ushort uint ulong"), - blockKeywords: words("catch class do else finally for foreach if struct switch try while"), - defKeywords: words("class interface namespace struct var"), - typeFirstDefinitions: true, - atoms: words("true false null"), - hooks: { - "@": function(stream, state) { - if (stream.eat('"')) { - state.tokenize = tokenAtString; - return tokenAtString(stream, state); - } - stream.eatWhile(/[\w\$_]/); - return "meta"; - } - } - }); - - function tokenTripleString(stream, state) { - var escaped = false; - while (!stream.eol()) { - if (!escaped && stream.match('"""')) { - state.tokenize = null; - break; - } - escaped = stream.next() == "\\" && !escaped; - } - return "string"; - } - - function tokenNestedComment(depth) { - return function (stream, state) { - var ch - while (ch = stream.next()) { - if (ch == "*" && stream.eat("/")) { - if (depth == 1) { - state.tokenize = null - break - } else { - state.tokenize = tokenNestedComment(depth - 1) - return state.tokenize(stream, state) - } - } else if (ch == "/" && stream.eat("*")) { - state.tokenize = tokenNestedComment(depth + 1) - return state.tokenize(stream, state) - } - } - return "comment" - } - } - - def("text/x-scala", { - name: "clike", - keywords: words( - - /* scala */ - "abstract case catch class def do else extends final finally for forSome if " + - "implicit import lazy match new null object override package private protected return " + - "sealed super this throw trait try type val var while with yield _ " + - - /* package scala */ - "assert assume require print println printf readLine readBoolean readByte readShort " + - "readChar readInt readLong readFloat readDouble" - ), - types: words( - "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + - "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " + - "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + - "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + - "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + - - /* package java.lang */ - "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + - "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + - "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + - "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" - ), - multiLineStrings: true, - blockKeywords: words("catch class enum do else finally for forSome if match switch try while"), - defKeywords: words("class enum def object package trait type val var"), - atoms: words("true false null"), - indentStatements: false, - indentSwitch: false, - isOperatorChar: /[+\-*&%=<>!?|\/#:@]/, - hooks: { - "@": function(stream) { - stream.eatWhile(/[\w\$_]/); - return "meta"; - }, - '"': function(stream, state) { - if (!stream.match('""')) return false; - state.tokenize = tokenTripleString; - return state.tokenize(stream, state); - }, - "'": function(stream) { - stream.eatWhile(/[\w\$_\xa1-\uffff]/); - return "atom"; - }, - "=": function(stream, state) { - var cx = state.context - if (cx.type == "}" && cx.align && stream.eat(">")) { - state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev) - return "operator" - } else { - return false - } - }, - - "/": function(stream, state) { - if (!stream.eat("*")) return false - state.tokenize = tokenNestedComment(1) - return state.tokenize(stream, state) - } - }, - modeProps: {closeBrackets: {triples: '"'}} - }); - - function tokenKotlinString(tripleString){ - return function (stream, state) { - var escaped = false, next, end = false; - while (!stream.eol()) { - if (!tripleString && !escaped && stream.match('"') ) {end = true; break;} - if (tripleString && stream.match('"""')) {end = true; break;} - next = stream.next(); - if(!escaped && next == "$" && stream.match('{')) - stream.skipTo("}"); - escaped = !escaped && next == "\\" && !tripleString; - } - if (end || !tripleString) - state.tokenize = null; - return "string"; - } - } - - def("text/x-kotlin", { - name: "clike", - keywords: words( - /*keywords*/ - "package as typealias class interface this super val operator " + - "var fun for is in This throw return annotation " + - "break continue object if else while do try when !in !is as? " + - - /*soft keywords*/ - "file import where by get set abstract enum open inner override private public internal " + - "protected catch finally out final vararg reified dynamic companion constructor init " + - "sealed field property receiver param sparam lateinit data inline noinline tailrec " + - "external annotation crossinline const operator infix suspend actual expect setparam" - ), - types: words( - /* package java.lang */ - "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + - "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + - "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + - "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " + - "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + - "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" - ), - intendSwitch: false, - indentStatements: false, - multiLineStrings: true, - number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, - blockKeywords: words("catch class do else finally for if where try while enum"), - defKeywords: words("class val var object interface fun"), - atoms: words("true false null this"), - hooks: { - "@": function(stream) { - stream.eatWhile(/[\w\$_]/); - return "meta"; - }, - '"': function(stream, state) { - state.tokenize = tokenKotlinString(stream.match('""')); - return state.tokenize(stream, state); - } - }, - modeProps: {closeBrackets: {triples: '"'}} - }); - - def(["x-shader/x-vertex", "x-shader/x-fragment"], { - name: "clike", - keywords: words("sampler1D sampler2D sampler3D samplerCube " + - "sampler1DShadow sampler2DShadow " + - "const attribute uniform varying " + - "break continue discard return " + - "for while do if else struct " + - "in out inout"), - types: words("float int bool void " + - "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " + - "mat2 mat3 mat4"), - blockKeywords: words("for while do if else struct"), - builtin: words("radians degrees sin cos tan asin acos atan " + - "pow exp log exp2 sqrt inversesqrt " + - "abs sign floor ceil fract mod min max clamp mix step smoothstep " + - "length distance dot cross normalize ftransform faceforward " + - "reflect refract matrixCompMult " + - "lessThan lessThanEqual greaterThan greaterThanEqual " + - "equal notEqual any all not " + - "texture1D texture1DProj texture1DLod texture1DProjLod " + - "texture2D texture2DProj texture2DLod texture2DProjLod " + - "texture3D texture3DProj texture3DLod texture3DProjLod " + - "textureCube textureCubeLod " + - "shadow1D shadow2D shadow1DProj shadow2DProj " + - "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " + - "dFdx dFdy fwidth " + - "noise1 noise2 noise3 noise4"), - atoms: words("true false " + - "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " + - "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " + - "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " + - "gl_FogCoord gl_PointCoord " + - "gl_Position gl_PointSize gl_ClipVertex " + - "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " + - "gl_TexCoord gl_FogFragCoord " + - "gl_FragCoord gl_FrontFacing " + - "gl_FragData gl_FragDepth " + - "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + - "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + - "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + - "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + - "gl_ProjectionMatrixInverseTranspose " + - "gl_ModelViewProjectionMatrixInverseTranspose " + - "gl_TextureMatrixInverseTranspose " + - "gl_NormalScale gl_DepthRange gl_ClipPlane " + - "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " + - "gl_FrontLightModelProduct gl_BackLightModelProduct " + - "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " + - "gl_FogParameters " + - "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " + - "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " + - "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " + - "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " + - "gl_MaxDrawBuffers"), - indentSwitch: false, - hooks: {"#": cppHook}, - modeProps: {fold: ["brace", "include"]} - }); - - def("text/x-nesc", { - name: "clike", - keywords: words(cKeywords + "as atomic async call command component components configuration event generic " + - "implementation includes interface module new norace nx_struct nx_union post provides " + - "signal task uses abstract extends"), - types: words(cTypes), - blockKeywords: words("case do else for if switch while struct"), - atoms: words("null true false"), - hooks: {"#": cppHook}, - modeProps: {fold: ["brace", "include"]} - }); - - def("text/x-objectivec", { - name: "clike", - keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " + - "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"), - types: words(cTypes), - atoms: words("YES NO NULL NILL ON OFF true false"), - hooks: { - "@": function(stream) { - stream.eatWhile(/[\w\$]/); - return "keyword"; - }, - "#": cppHook, - indent: function(_state, ctx, textAfter) { - if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented - } - }, - modeProps: {fold: "brace"} - }); - - def("text/x-squirrel", { - name: "clike", - keywords: words("base break clone continue const default delete enum extends function in class" + - " foreach local resume return this throw typeof yield constructor instanceof static"), - types: words(cTypes), - blockKeywords: words("case catch class else for foreach if switch try while"), - defKeywords: words("function local class"), - typeFirstDefinitions: true, - atoms: words("true false null"), - hooks: {"#": cppHook}, - modeProps: {fold: ["brace", "include"]} - }); - - // Ceylon Strings need to deal with interpolation - var stringTokenizer = null; - function tokenCeylonString(type) { - return function(stream, state) { - var escaped = false, next, end = false; - while (!stream.eol()) { - if (!escaped && stream.match('"') && - (type == "single" || stream.match('""'))) { - end = true; - break; - } - if (!escaped && stream.match('``')) { - stringTokenizer = tokenCeylonString(type); - end = true; - break; - } - next = stream.next(); - escaped = type == "single" && !escaped && next == "\\"; - } - if (end) - state.tokenize = null; - return "string"; - } - } - - def("text/x-ceylon", { - name: "clike", - keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" + - " exists extends finally for function given if import in interface is let module new" + - " nonempty object of out outer package return satisfies super switch then this throw" + - " try value void while"), - types: function(word) { - // In Ceylon all identifiers that start with an uppercase are types - var first = word.charAt(0); - return (first === first.toUpperCase() && first !== first.toLowerCase()); - }, - blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"), - defKeywords: words("class dynamic function interface module object package value"), - builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" + - " native optional sealed see serializable shared suppressWarnings tagged throws variable"), - isPunctuationChar: /[\[\]{}\(\),;\:\.`]/, - isOperatorChar: /[+\-*&%=<>!?|^~:\/]/, - numberStart: /[\d#$]/, - number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i, - multiLineStrings: true, - typeFirstDefinitions: true, - atoms: words("true false null larger smaller equal empty finished"), - indentSwitch: false, - styleDefs: false, - hooks: { - "@": function(stream) { - stream.eatWhile(/[\w\$_]/); - return "meta"; - }, - '"': function(stream, state) { - state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single"); - return state.tokenize(stream, state); - }, - '`': function(stream, state) { - if (!stringTokenizer || !stream.match('`')) return false; - state.tokenize = stringTokenizer; - stringTokenizer = null; - return state.tokenize(stream, state); - }, - "'": function(stream) { - stream.eatWhile(/[\w\$_\xa1-\uffff]/); - return "atom"; - }, - token: function(_stream, state, style) { - if ((style == "variable" || style == "type") && - state.prevToken == ".") { - return "variable-2"; - } - } - }, - modeProps: { - fold: ["brace", "import"], - closeBrackets: {triples: '"'} - } - }); - - }); - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* 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/. */ - - // WebAssembly experimental syntax highlight add-on for CodeMirror. - - (function (root, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(2)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else if (typeof exports !== 'undefined') { - factory(require("../../lib/codemirror")); - } else { - factory(root.CodeMirror); - } - }(this, function (CodeMirror) { - "use strict"; - - var isWordChar = /[\w\$_\.\\\/@]/; - - function createLookupTable(list) { - var obj = Object.create(null); - list.forEach(function (key) { - obj[key] = true; - }); - return obj; - } - - CodeMirror.defineMode("wasm", function() { - var keywords = createLookupTable([ - "function", "import", "export", "table", "memory", "segment", "as", "type", - "of", "from", "typeof", "br", "br_if", "loop", "br_table", "if", "else", - "call", "call_import", "call_indirect", "nop", "unreachable", "var", - "align", "select", "return"]); - var builtins = createLookupTable([ - "i32:8", "i32:8u", "i32:8s", "i32:16", "i32:16u", "i32:16s", - "i64:8", "i64:8u", "i64:8s", "i64:16", "i64:16u", "i64:16s", - "i64:32", "i64:32u", "i64:32s", - "i32.add", "i32.sub", "i32.mul", "i32.div_s", "i32.div_u", - "i32.rem_s", "i32.rem_u", "i32.and", "i32.or", "i32.xor", - "i32.shl", "i32.shr_u", "i32.shr_s", "i32.rotr", "i32.rotl", - "i32.eq", "i32.ne", "i32.lt_s", "i32.le_s", "i32.lt_u", - "i32.le_u", "i32.gt_s", "i32.ge_s", "i32.gt_u", "i32.ge_u", - "i32.clz", "i32.ctz", "i32.popcnt", "i32.eqz", "i64.add", - "i64.sub", "i64.mul", "i64.div_s", "i64.div_u", "i64.rem_s", - "i64.rem_u", "i64.and", "i64.or", "i64.xor", "i64.shl", - "i64.shr_u", "i64.shr_s", "i64.rotr", "i64.rotl", "i64.eq", - "i64.ne", "i64.lt_s", "i64.le_s", "i64.lt_u", "i64.le_u", - "i64.gt_s", "i64.ge_s", "i64.gt_u", "i64.ge_u", "i64.clz", - "i64.ctz", "i64.popcnt", "i64.eqz", "f32.add", "f32.sub", - "f32.mul", "f32.div", "f32.min", "f32.max", "f32.abs", - "f32.neg", "f32.copysign", "f32.ceil", "f32.floor", "f32.trunc", - "f32.nearest", "f32.sqrt", "f32.eq", "f32.ne", "f32.lt", - "f32.le", "f32.gt", "f32.ge", "f64.add", "f64.sub", "f64.mul", - "f64.div", "f64.min", "f64.max", "f64.abs", "f64.neg", - "f64.copysign", "f64.ceil", "f64.floor", "f64.trunc", "f64.nearest", - "f64.sqrt", "f64.eq", "f64.ne", "f64.lt", "f64.le", "f64.gt", - "f64.ge", "i32.trunc_s/f32", "i32.trunc_s/f64", "i32.trunc_u/f32", - "i32.trunc_u/f64", "i32.wrap/i64", "i64.trunc_s/f32", - "i64.trunc_s/f64", "i64.trunc_u/f32", "i64.trunc_u/f64", - "i64.extend_s/i32", "i64.extend_u/i32", "f32.convert_s/i32", - "f32.convert_u/i32", "f32.convert_s/i64", "f32.convert_u/i64", - "f32.demote/f64", "f32.reinterpret/i32", "f64.convert_s/i32", - "f64.convert_u/i32", "f64.convert_s/i64", "f64.convert_u/i64", - "f64.promote/f32", "f64.reinterpret/i64", "i32.reinterpret/f32", - "i64.reinterpret/f64"]); - var dataTypes = createLookupTable(["i32", "i64", "f32", "f64"]); - var isUnaryOperator = /[\-!]/; - var operators = createLookupTable([ - "+", "-", "*", "/", "/s", "/u", "%", "%s", "%u", - "<<", ">>u", ">>s", ">=", "<=", "==", "!=", - "=s", ">=u", ">s", ">u", - "<", ">", "=", "&", "|", "^", "!"]); - - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch === "$") { - stream.eatWhile(isWordChar); - return "variable"; - } - if (ch === "@") { - stream.eatWhile(isWordChar); - return "meta"; - } - if (ch === '"') { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } - if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return "comment"; - } - } - if (/\d/.test(ch) || - ((ch === "-" || ch === "+") && /\d/.test(stream.peek()))) { - stream.eatWhile(/[\w\._\-+]/); - return "number"; - } - if (/[\[\]\(\)\{\},:]/.test(ch)) { - return null; - } - if (isUnaryOperator.test(ch)) { - return "operator"; - } - stream.eatWhile(isWordChar); - var word = stream.current(); - - if (word in operators) { - return "operator"; - } - if (word in keywords){ - return "keyword"; - } - if (word in dataTypes) { - if (!stream.eat(":")) { - return "builtin"; - } - stream.eatWhile(isWordChar); - word = stream.current(); - // fall thru for "builtin" check - } - if (word in builtins) { - return "builtin"; - } - - if (word === "Temporary") { - // Nightly has header with some text graphics -- skipping it. - state.tokenize = tokenTemporary; - return state.tokenize(stream, state); - } - return null; - } - - function tokenComment(stream, state) { - state.commentDepth = 1; - var next; - while ((next = stream.next()) != null) { - if (next === "*" && stream.eat("/")) { - if (--state.commentDepth === 0) { - state.tokenize = null; - return "comment"; - } - } - if (next === "/" && stream.eat("*")) { - // Nested comment - state.commentDepth++; - } - } - return "comment"; - } - - function tokenTemporary(stream, state) { - var next, endState = state.commentState; - // Skipping until "text support (Work In Progress):" is found. - while ((next = stream.next()) != null) { - if (endState === 0 && next === "t") { - endState = 1; - } else if (endState === 1 && next === ":") { - state.tokenize = null; - state.commentState = 0; - endState = 2; - return "comment"; - } - } - state.commentState = endState; - return "comment"; - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) { - state.tokenize = null; - return "string"; - } - escaped = !escaped && next === "\\"; - } - return "string"; - }; - } - - return { - startState: function() { - return {tokenize: null, commentState: 0, commentDepth: 0}; - }, - - token: function(stream, state) { - if (stream.eatSpace()) return null; - var style = (state.tokenize || tokenBase)(stream, state); - return style; - } - }; - }); - - CodeMirror.registerHelper("wordChars", "wasm", isWordChar); - - CodeMirror.defineMIME("text/wasm", "wasm"); - - })); - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - var WRAP_CLASS = "CodeMirror-activeline"; - var BACK_CLASS = "CodeMirror-activeline-background"; - var GUTT_CLASS = "CodeMirror-activeline-gutter"; - - CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { - var prev = old == CodeMirror.Init ? false : old; - if (val == prev) return - if (prev) { - cm.off("beforeSelectionChange", selectionChange); - clearActiveLines(cm); - delete cm.state.activeLines; - } - if (val) { - cm.state.activeLines = []; - updateActiveLines(cm, cm.listSelections()); - cm.on("beforeSelectionChange", selectionChange); - } - }); - - function clearActiveLines(cm) { - for (var i = 0; i < cm.state.activeLines.length; i++) { - cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); - cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); - cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); - } - } - - function sameArray(a, b) { - if (a.length != b.length) return false; - for (var i = 0; i < a.length; i++) - if (a[i] != b[i]) return false; - return true; - } - - function updateActiveLines(cm, ranges) { - var active = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - var option = cm.getOption("styleActiveLine"); - if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) - continue - var line = cm.getLineHandleVisualStart(range.head.line); - if (active[active.length - 1] != line) active.push(line); - } - if (sameArray(cm.state.activeLines, active)) return; - cm.operation(function() { - clearActiveLines(cm); - for (var i = 0; i < active.length; i++) { - cm.addLineClass(active[i], "wrap", WRAP_CLASS); - cm.addLineClass(active[i], "background", BACK_CLASS); - cm.addLineClass(active[i], "gutter", GUTT_CLASS); - } - cm.state.activeLines = active; - }); - } - - function selectionChange(cm, sel) { - updateActiveLines(cm, sel.ranges); - } - }); - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { - if (prev == CodeMirror.Init) prev = false; - if (prev && !val) - cm.removeOverlay("trailingspace"); - else if (!prev && val) - cm.addOverlay({ - token: function(stream) { - for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} - if (i > stream.pos) { stream.pos = i; return null; } - stream.pos = l; - return "trailingspace"; - }, - name: "trailingspace" - }); - }); - }); - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var Pos = CodeMirror.Pos; - function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } - - // Kill 'ring' - - var killRing = []; - function addToRing(str) { - killRing.push(str); - if (killRing.length > 50) killRing.shift(); - } - function growRingTop(str) { - if (!killRing.length) return addToRing(str); - killRing[killRing.length - 1] += str; - } - function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; } - function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); } - - var lastKill = null; - - function kill(cm, from, to, ring, text) { - if (text == null) text = cm.getRange(from, to); - - if (ring == "grow" && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) - growRingTop(text); - else if (ring !== false) - addToRing(text); - cm.replaceRange("", from, to, "+delete"); - - if (ring == "grow") lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; - else lastKill = null; - } - - // Boundaries of various units - - function byChar(cm, pos, dir) { - return cm.findPosH(pos, dir, "char", true); - } - - function byWord(cm, pos, dir) { - return cm.findPosH(pos, dir, "word", true); - } - - function byLine(cm, pos, dir) { - return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn); - } - - function byPage(cm, pos, dir) { - return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn); - } - - function byParagraph(cm, pos, dir) { - var no = pos.line, line = cm.getLine(no); - var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch)); - var fst = cm.firstLine(), lst = cm.lastLine(); - for (;;) { - no += dir; - if (no < fst || no > lst) - return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null)); - line = cm.getLine(no); - var hasText = /\S/.test(line); - if (hasText) sawText = true; - else if (sawText) return Pos(no, 0); - } - } - - function bySentence(cm, pos, dir) { - var line = pos.line, ch = pos.ch; - var text = cm.getLine(pos.line), sawWord = false; - for (;;) { - var next = text.charAt(ch + (dir < 0 ? -1 : 0)); - if (!next) { // End/beginning of line reached - if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch); - text = cm.getLine(line + dir); - if (!/\S/.test(text)) return Pos(line, ch); - line += dir; - ch = dir < 0 ? text.length : 0; - continue; - } - if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0)); - if (!sawWord) sawWord = /\w/.test(next); - ch += dir; - } - } - - function byExpr(cm, pos, dir) { - var wrap; - if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, {strict: true})) - && wrap.match && (wrap.forward ? 1 : -1) == dir) - return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to; - - for (var first = true;; first = false) { - var token = cm.getTokenAt(pos); - var after = Pos(pos.line, dir < 0 ? token.start : token.end); - if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) { - var newPos = cm.findPosH(after, dir, "char"); - if (posEq(after, newPos)) return pos; - else pos = newPos; - } else { - return after; - } - } - } - - // Prefixes (only crudely supported) - - function getPrefix(cm, precise) { - var digits = cm.state.emacsPrefix; - if (!digits) return precise ? null : 1; - clearPrefix(cm); - return digits == "-" ? -1 : Number(digits); - } - - function repeated(cmd) { - var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd; - return function(cm) { - var prefix = getPrefix(cm); - f(cm); - for (var i = 1; i < prefix; ++i) f(cm); - }; - } - - function findEnd(cm, pos, by, dir) { - var prefix = getPrefix(cm); - if (prefix < 0) { dir = -dir; prefix = -prefix; } - for (var i = 0; i < prefix; ++i) { - var newPos = by(cm, pos, dir); - if (posEq(newPos, pos)) break; - pos = newPos; - } - return pos; - } - - function move(by, dir) { - var f = function(cm) { - cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir)); - }; - f.motion = true; - return f; - } - - function killTo(cm, by, dir, ring) { - var selections = cm.listSelections(), cursor; - var i = selections.length; - while (i--) { - cursor = selections[i].head; - kill(cm, cursor, findEnd(cm, cursor, by, dir), ring); - } - } - - function killRegion(cm, ring) { - if (cm.somethingSelected()) { - var selections = cm.listSelections(), selection; - var i = selections.length; - while (i--) { - selection = selections[i]; - kill(cm, selection.anchor, selection.head, ring); - } - return true; - } - } - - function addPrefix(cm, digit) { - if (cm.state.emacsPrefix) { - if (digit != "-") cm.state.emacsPrefix += digit; - return; - } - // Not active yet - cm.state.emacsPrefix = digit; - cm.on("keyHandled", maybeClearPrefix); - cm.on("inputRead", maybeDuplicateInput); - } - - var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true}; - - function maybeClearPrefix(cm, arg) { - if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg)) - clearPrefix(cm); - } - - function clearPrefix(cm) { - cm.state.emacsPrefix = null; - cm.off("keyHandled", maybeClearPrefix); - cm.off("inputRead", maybeDuplicateInput); - } - - function maybeDuplicateInput(cm, event) { - var dup = getPrefix(cm); - if (dup > 1 && event.origin == "+input") { - var one = event.text.join("\n"), txt = ""; - for (var i = 1; i < dup; ++i) txt += one; - cm.replaceSelection(txt); - } - } - - function addPrefixMap(cm) { - cm.state.emacsPrefixMap = true; - cm.addKeyMap(prefixMap); - cm.on("keyHandled", maybeRemovePrefixMap); - cm.on("inputRead", maybeRemovePrefixMap); - } - - function maybeRemovePrefixMap(cm, arg) { - if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return; - cm.removeKeyMap(prefixMap); - cm.state.emacsPrefixMap = false; - cm.off("keyHandled", maybeRemovePrefixMap); - cm.off("inputRead", maybeRemovePrefixMap); - } - - // Utilities - - function setMark(cm) { - cm.setCursor(cm.getCursor()); - cm.setExtending(!cm.getExtending()); - cm.on("change", function() { cm.setExtending(false); }); - } - - function clearMark(cm) { - cm.setExtending(false); - cm.setCursor(cm.getCursor()); - } - - function getInput(cm, msg, f) { - if (cm.openDialog) - cm.openDialog(msg + ": ", f, {bottom: true}); - else - f(prompt(msg, "")); - } - - function operateOnWord(cm, op) { - var start = cm.getCursor(), end = cm.findPosH(start, 1, "word"); - cm.replaceRange(op(cm.getRange(start, end)), start, end); - cm.setCursor(end); - } - - function toEnclosingExpr(cm) { - var pos = cm.getCursor(), line = pos.line, ch = pos.ch; - var stack = []; - while (line >= cm.firstLine()) { - var text = cm.getLine(line); - for (var i = ch == null ? text.length : ch; i > 0;) { - var ch = text.charAt(--i); - if (ch == ")") - stack.push("("); - else if (ch == "]") - stack.push("["); - else if (ch == "}") - stack.push("{"); - else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch)) - return cm.extendSelection(Pos(line, i)); - } - --line; ch = null; - } - } - - function quit(cm) { - cm.execCommand("clearSearch"); - clearMark(cm); - } - - CodeMirror.emacs = {kill: kill, killRegion: killRegion, repeated: repeated}; - - // Actual keymap - - var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({ - "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"), true);}, - "Ctrl-K": repeated(function(cm) { - var start = cm.getCursor(), end = cm.clipPos(Pos(start.line)); - var text = cm.getRange(start, end); - if (!/\S/.test(text)) { - text += "\n"; - end = Pos(start.line + 1, 0); - } - kill(cm, start, end, "grow", text); - }), - "Alt-W": function(cm) { - addToRing(cm.getSelection()); - clearMark(cm); - }, - "Ctrl-Y": function(cm) { - var start = cm.getCursor(); - cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste"); - cm.setSelection(start, cm.getCursor()); - }, - "Alt-Y": function(cm) {cm.replaceSelection(popFromRing(), "around", "paste");}, - - "Ctrl-Space": setMark, "Ctrl-Shift-2": setMark, - - "Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1), - "Right": move(byChar, 1), "Left": move(byChar, -1), - "Ctrl-D": function(cm) { killTo(cm, byChar, 1, false); }, - "Delete": function(cm) { killRegion(cm, false) || killTo(cm, byChar, 1, false); }, - "Ctrl-H": function(cm) { killTo(cm, byChar, -1, false); }, - "Backspace": function(cm) { killRegion(cm, false) || killTo(cm, byChar, -1, false); }, - - "Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1), - "Alt-Right": move(byWord, 1), "Alt-Left": move(byWord, -1), - "Alt-D": function(cm) { killTo(cm, byWord, 1, "grow"); }, - "Alt-Backspace": function(cm) { killTo(cm, byWord, -1, "grow"); }, - - "Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1), - "Down": move(byLine, 1), "Up": move(byLine, -1), - "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "End": "goLineEnd", "Home": "goLineStart", - - "Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1), - "PageUp": move(byPage, -1), "PageDown": move(byPage, 1), - - "Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1), - - "Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1), - "Alt-K": function(cm) { killTo(cm, bySentence, 1, "grow"); }, - - "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1, "grow"); }, - "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1, "grow"); }, - "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1, "grow"), - - "Shift-Ctrl-Alt-2": function(cm) { - var cursor = cm.getCursor(); - cm.setSelection(findEnd(cm, cursor, byExpr, 1), cursor); - }, - "Ctrl-Alt-T": function(cm) { - var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1); - var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1); - cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) + - cm.getRange(leftStart, leftEnd), leftStart, rightEnd); - }, - "Ctrl-Alt-U": repeated(toEnclosingExpr), - - "Alt-Space": function(cm) { - var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line); - while (from && /\s/.test(text.charAt(from - 1))) --from; - while (to < text.length && /\s/.test(text.charAt(to))) ++to; - cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to)); - }, - "Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }), - "Ctrl-T": repeated(function(cm) { - cm.execCommand("transposeChars"); - }), - - "Alt-C": repeated(function(cm) { - operateOnWord(cm, function(w) { - var letter = w.search(/\w/); - if (letter == -1) return w; - return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase(); - }); - }), - "Alt-U": repeated(function(cm) { - operateOnWord(cm, function(w) { return w.toUpperCase(); }); - }), - "Alt-L": repeated(function(cm) { - operateOnWord(cm, function(w) { return w.toLowerCase(); }); - }), - - "Alt-;": "toggleComment", - - "Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"), - "Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"), - "Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd", - "Ctrl-S": "findPersistentNext", "Ctrl-R": "findPersistentPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace", - "Alt-/": "autocomplete", - "Enter": "newlineAndIndent", - "Ctrl-J": repeated(function(cm) { cm.replaceSelection("\n", "end"); }), - "Tab": "indentAuto", - - "Alt-G G": function(cm) { - var prefix = getPrefix(cm, true); - if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1); - - getInput(cm, "Goto line", function(str) { - var num; - if (str && !isNaN(num = Number(str)) && num == (num|0) && num > 0) - cm.setCursor(num - 1); - }); - }, - - "Ctrl-X Tab": function(cm) { - cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit")); - }, - "Ctrl-X Ctrl-X": function(cm) { - cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor")); - }, - "Ctrl-X Ctrl-S": "save", - "Ctrl-X Ctrl-W": "save", - "Ctrl-X S": "saveAll", - "Ctrl-X F": "open", - "Ctrl-X U": repeated("undo"), - "Ctrl-X K": "close", - "Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), "grow"); }, - "Ctrl-X H": "selectAll", - - "Ctrl-Q Tab": repeated("insertTab"), - "Ctrl-U": addPrefixMap - }); - - var prefixMap = {"Ctrl-G": clearPrefix}; - function regPrefix(d) { - prefixMap[d] = function(cm) { addPrefix(cm, d); }; - keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); }; - prefixPreservingKeys["Ctrl-" + d] = true; - } - for (var i = 0; i < 10; ++i) regPrefix(String(i)); - regPrefix("-"); - }); - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - /** - * Supported keybindings: - * Too many to list. Refer to defaultKeyMap below. - * - * Supported Ex commands: - * Refer to defaultExCommandMap below. - * - * Registers: unnamed, -, a-z, A-Z, 0-9 - * (Does not respect the special case for number registers when delete - * operator is made with these commands: %, (, ), , /, ?, n, N, {, } ) - * TODO: Implement the remaining registers. - * - * Marks: a-z, A-Z, and 0-9 - * TODO: Implement the remaining special marks. They have more complex - * behavior. - * - * Events: - * 'vim-mode-change' - raised on the editor anytime the current mode changes, - * Event object: {mode: "visual", subMode: "linewise"} - * - * Code structure: - * 1. Default keymap - * 2. Variable declarations and short basic helpers - * 3. Instance (External API) implementation - * 4. Internal state tracking objects (input state, counter) implementation - * and instantiation - * 5. Key handler (the main command dispatcher) implementation - * 6. Motion, operator, and action implementations - * 7. Helper functions for the key handler, motions, operators, and actions - * 8. Set up Vim to work as a keymap for CodeMirror. - * 9. Ex command implementations. - */ - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(3), __webpack_require__(1), __webpack_require__(5)); - else if (typeof define == "function" && define.amd) // AMD - define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/dialog/dialog", "../addon/edit/matchbrackets"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - 'use strict'; - - var defaultKeymap = [ - // Key to key mapping. This goes first to make it possible to override - // existing mappings. - { keys: '', type: 'keyToKey', toKeys: 'h' }, - { keys: '', type: 'keyToKey', toKeys: 'l' }, - { keys: '', type: 'keyToKey', toKeys: 'k' }, - { keys: '', type: 'keyToKey', toKeys: 'j' }, - { keys: '', type: 'keyToKey', toKeys: 'l' }, - { keys: '', type: 'keyToKey', toKeys: 'h', context: 'normal'}, - { keys: '', type: 'keyToKey', toKeys: 'W' }, - { keys: '', type: 'keyToKey', toKeys: 'B', context: 'normal' }, - { keys: '', type: 'keyToKey', toKeys: 'w' }, - { keys: '', type: 'keyToKey', toKeys: 'b', context: 'normal' }, - { keys: '', type: 'keyToKey', toKeys: 'j' }, - { keys: '', type: 'keyToKey', toKeys: 'k' }, - { keys: '', type: 'keyToKey', toKeys: '' }, - { keys: '', type: 'keyToKey', toKeys: '' }, - { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, - { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, - { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' }, - { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'}, - { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' }, - { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' }, - { keys: '', type: 'keyToKey', toKeys: '0' }, - { keys: '', type: 'keyToKey', toKeys: '$' }, - { keys: '', type: 'keyToKey', toKeys: '' }, - { keys: '', type: 'keyToKey', toKeys: '' }, - { keys: '', type: 'keyToKey', toKeys: 'j^', context: 'normal' }, - { keys: '', type: 'action', action: 'toggleOverwrite', context: 'insert' }, - // Motions - { keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }}, - { keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }}, - { keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }}, - { keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }}, - { keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }}, - { keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }}, - { keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }}, - { keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }}, - { keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }}, - { keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }}, - { keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }}, - { keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }}, - { keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }}, - { keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }}, - { keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }}, - { keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }}, - { keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, - { keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }}, - { keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }}, - { keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }}, - { keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }}, - { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, - { keys: '', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, - { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }}, - { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }}, - { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, - { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, - { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, - { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, - { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }}, - { keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }}, - { keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }}, - { keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }}, - { keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }}, - { keys: 'f', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }}, - { keys: 'F', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }}, - { keys: 't', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }}, - { keys: 'T', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }}, - { keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }}, - { keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }}, - { keys: '\'', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}}, - { keys: '`', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}}, - { keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, - { keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, - { keys: ']\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, - { keys: '[\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, - // the next two aren't motions but must come before more general motion declarations - { keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}}, - { keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}}, - { keys: ']', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}}, - { keys: '[', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}}, - { keys: '|', type: 'motion', motion: 'moveToColumn'}, - { keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'}, - { keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'}, - // Operators - { keys: 'd', type: 'operator', operator: 'delete' }, - { keys: 'y', type: 'operator', operator: 'yank' }, - { keys: 'c', type: 'operator', operator: 'change' }, - { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }}, - { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }}, - { keys: 'g~', type: 'operator', operator: 'changeCase' }, - { keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, isEdit: true }, - { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true }, - { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, - { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, - // Operator-Motion dual commands - { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }}, - { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, - { keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, - { keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'}, - { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'expandToLine', motionArgs: { linewise: true }, context: 'normal'}, - { keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'}, - { keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'}, - { keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'}, - { keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'}, - { keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'}, - { keys: '', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' }, - // Actions - { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }}, - { keys: '', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }}, - { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }}, - { keys: '', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }}, - { keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' }, - { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' }, - { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, - { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' }, - { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' }, - { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' }, - { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' }, - { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' }, - { keys: 'v', type: 'action', action: 'toggleVisualMode' }, - { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }}, - { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, - { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }}, - { keys: 'gv', type: 'action', action: 'reselectLastSelection' }, - { keys: 'J', type: 'action', action: 'joinLines', isEdit: true }, - { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }}, - { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }}, - { keys: 'r', type: 'action', action: 'replace', isEdit: true }, - { keys: '@', type: 'action', action: 'replayMacro' }, - { keys: 'q', type: 'action', action: 'enterMacroRecordMode' }, - // Handle Replace-mode as a special case of insert mode. - { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }}, - { keys: 'u', type: 'action', action: 'undo', context: 'normal' }, - { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true }, - { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true }, - { keys: '', type: 'action', action: 'redo' }, - { keys: 'm', type: 'action', action: 'setMark' }, - { keys: '"', type: 'action', action: 'setRegister' }, - { keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }}, - { keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, - { keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }}, - { keys: 'z', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, - { keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }}, - { keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, - { keys: '.', type: 'action', action: 'repeatLastEdit' }, - { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}}, - { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}}, - { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: true }, context: 'insert' }, - { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: false }, context: 'insert' }, - // Text object motions - { keys: 'a', type: 'motion', motion: 'textObjectManipulation' }, - { keys: 'i', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }}, - // Search - { keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }}, - { keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, - { keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, - { keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }}, - { keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, - { keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, - // Ex command - { keys: ':', type: 'ex' } - ]; - - /** - * Ex commands - * Care must be taken when adding to the default Ex command map. For any - * pair of commands that have a shared prefix, at least one of their - * shortNames must not match the prefix of the other command. - */ - var defaultExCommandMap = [ - { name: 'colorscheme', shortName: 'colo' }, - { name: 'map' }, - { name: 'imap', shortName: 'im' }, - { name: 'nmap', shortName: 'nm' }, - { name: 'vmap', shortName: 'vm' }, - { name: 'unmap' }, - { name: 'write', shortName: 'w' }, - { name: 'undo', shortName: 'u' }, - { name: 'redo', shortName: 'red' }, - { name: 'set', shortName: 'se' }, - { name: 'set', shortName: 'se' }, - { name: 'setlocal', shortName: 'setl' }, - { name: 'setglobal', shortName: 'setg' }, - { name: 'sort', shortName: 'sor' }, - { name: 'substitute', shortName: 's', possiblyAsync: true }, - { name: 'nohlsearch', shortName: 'noh' }, - { name: 'yank', shortName: 'y' }, - { name: 'delmarks', shortName: 'delm' }, - { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true }, - { name: 'global', shortName: 'g' } - ]; - - var Pos = CodeMirror.Pos; - - var Vim = function() { - function enterVimMode(cm) { - cm.setOption('disableInput', true); - cm.setOption('showCursorWhenSelecting', false); - CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); - cm.on('cursorActivity', onCursorActivity); - maybeInitVimState(cm); - CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm)); - } - - function leaveVimMode(cm) { - cm.setOption('disableInput', false); - cm.off('cursorActivity', onCursorActivity); - CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm)); - cm.state.vim = null; - } - - function detachVimMap(cm, next) { - if (this == CodeMirror.keyMap.vim) { - CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); - if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) { - disableFatCursorMark(cm); - cm.getInputField().style.caretColor = ""; - } - } - - if (!next || next.attach != attachVimMap) - leaveVimMode(cm); - } - function attachVimMap(cm, prev) { - if (this == CodeMirror.keyMap.vim) { - CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); - if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) { - enableFatCursorMark(cm); - cm.getInputField().style.caretColor = "transparent"; - } - } - - if (!prev || prev.attach != attachVimMap) - enterVimMode(cm); - } - - function fatCursorMarks(cm) { - var ranges = cm.listSelections(), result = [] - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i] - if (range.empty()) { - if (range.anchor.ch < cm.getLine(range.anchor.line).length) { - result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1), - {className: "cm-fat-cursor-mark"})) - } else { - var widget = document.createElement("span") - widget.textContent = "\u00a0" - widget.className = "cm-fat-cursor-mark" - result.push(cm.setBookmark(range.anchor, {widget: widget})) - } - } - } - return result - } - - function updateFatCursorMark(cm) { - var marks = cm.state.fatCursorMarks - if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear() - cm.state.fatCursorMarks = fatCursorMarks(cm) - } - - function enableFatCursorMark(cm) { - cm.state.fatCursorMarks = fatCursorMarks(cm) - cm.on("cursorActivity", updateFatCursorMark) - } - - function disableFatCursorMark(cm) { - var marks = cm.state.fatCursorMarks - if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear() - cm.state.fatCursorMarks = null - cm.off("cursorActivity", updateFatCursorMark) - } - - // Deprecated, simply setting the keymap works again. - CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { - if (val && cm.getOption("keyMap") != "vim") - cm.setOption("keyMap", "vim"); - else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) - cm.setOption("keyMap", "default"); - }); - - function cmKey(key, cm) { - if (!cm) { return undefined; } - if (this[key]) { return this[key]; } - var vimKey = cmKeyToVimKey(key); - if (!vimKey) { - return false; - } - var cmd = CodeMirror.Vim.findKey(cm, vimKey); - if (typeof cmd == 'function') { - CodeMirror.signal(cm, 'vim-keypress', vimKey); - } - return cmd; - } - - var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'}; - var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'}; - function cmKeyToVimKey(key) { - if (key.charAt(0) == '\'') { - // Keypress character binding of format "'a'" - return key.charAt(1); - } - var pieces = key.split(/-(?!$)/); - var lastPiece = pieces[pieces.length - 1]; - if (pieces.length == 1 && pieces[0].length == 1) { - // No-modifier bindings use literal character bindings above. Skip. - return false; - } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { - // Ignore Shift+char bindings as they should be handled by literal character. - return false; - } - var hasCharacter = false; - for (var i = 0; i < pieces.length; i++) { - var piece = pieces[i]; - if (piece in modifiers) { pieces[i] = modifiers[piece]; } - else { hasCharacter = true; } - if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } - } - if (!hasCharacter) { - // Vim does not support modifier only keys. - return false; - } - // TODO: Current bindings expect the character to be lower case, but - // it looks like vim key notation uses upper case. - if (isUpperCase(lastPiece)) { - pieces[pieces.length - 1] = lastPiece.toLowerCase(); - } - return '<' + pieces.join('-') + '>'; - } - - function getOnPasteFn(cm) { - var vim = cm.state.vim; - if (!vim.onPasteFn) { - vim.onPasteFn = function() { - if (!vim.insertMode) { - cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); - actions.enterInsertMode(cm, {}, vim); - } - }; - } - return vim.onPasteFn; - } - - var numberRegex = /[\d]/; - var wordCharTest = [CodeMirror.isWordChar, function(ch) { - return ch && !CodeMirror.isWordChar(ch) && !/\s/.test(ch); - }], bigWordCharTest = [function(ch) { - return /\S/.test(ch); - }]; - function makeKeyRange(start, size) { - var keys = []; - for (var i = start; i < start + size; i++) { - keys.push(String.fromCharCode(i)); - } - return keys; - } - var upperCaseAlphabet = makeKeyRange(65, 26); - var lowerCaseAlphabet = makeKeyRange(97, 26); - var numbers = makeKeyRange(48, 10); - var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); - var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '/']); - - function isLine(cm, line) { - return line >= cm.firstLine() && line <= cm.lastLine(); - } - function isLowerCase(k) { - return (/^[a-z]$/).test(k); - } - function isMatchableSymbol(k) { - return '()[]{}'.indexOf(k) != -1; - } - function isNumber(k) { - return numberRegex.test(k); - } - function isUpperCase(k) { - return (/^[A-Z]$/).test(k); - } - function isWhiteSpaceString(k) { - return (/^\s*$/).test(k); - } - function isEndOfSentenceSymbol(k) { - return '.?!'.indexOf(k) != -1; - } - function inArray(val, arr) { - for (var i = 0; i < arr.length; i++) { - if (arr[i] == val) { - return true; - } - } - return false; - } - - var options = {}; - function defineOption(name, defaultValue, type, aliases, callback) { - if (defaultValue === undefined && !callback) { - throw Error('defaultValue is required unless callback is provided'); - } - if (!type) { type = 'string'; } - options[name] = { - type: type, - defaultValue: defaultValue, - callback: callback - }; - if (aliases) { - for (var i = 0; i < aliases.length; i++) { - options[aliases[i]] = options[name]; - } - } - if (defaultValue) { - setOption(name, defaultValue); - } - } - - function setOption(name, value, cm, cfg) { - var option = options[name]; - cfg = cfg || {}; - var scope = cfg.scope; - if (!option) { - return new Error('Unknown option: ' + name); - } - if (option.type == 'boolean') { - if (value && value !== true) { - return new Error('Invalid argument: ' + name + '=' + value); - } else if (value !== false) { - // Boolean options are set to true if value is not defined. - value = true; - } - } - if (option.callback) { - if (scope !== 'local') { - option.callback(value, undefined); - } - if (scope !== 'global' && cm) { - option.callback(value, cm); - } - } else { - if (scope !== 'local') { - option.value = option.type == 'boolean' ? !!value : value; - } - if (scope !== 'global' && cm) { - cm.state.vim.options[name] = {value: value}; - } - } - } - - function getOption(name, cm, cfg) { - var option = options[name]; - cfg = cfg || {}; - var scope = cfg.scope; - if (!option) { - return new Error('Unknown option: ' + name); - } - if (option.callback) { - var local = cm && option.callback(undefined, cm); - if (scope !== 'global' && local !== undefined) { - return local; - } - if (scope !== 'local') { - return option.callback(); - } - return; - } else { - var local = (scope !== 'global') && (cm && cm.state.vim.options[name]); - return (local || (scope !== 'local') && option || {}).value; - } - } - - defineOption('filetype', undefined, 'string', ['ft'], function(name, cm) { - // Option is local. Do nothing for global. - if (cm === undefined) { - return; - } - // The 'filetype' option proxies to the CodeMirror 'mode' option. - if (name === undefined) { - var mode = cm.getOption('mode'); - return mode == 'null' ? '' : mode; - } else { - var mode = name == '' ? 'null' : name; - cm.setOption('mode', mode); - } - }); - - var createCircularJumpList = function() { - var size = 100; - var pointer = -1; - var head = 0; - var tail = 0; - var buffer = new Array(size); - function add(cm, oldCur, newCur) { - var current = pointer % size; - var curMark = buffer[current]; - function useNextSlot(cursor) { - var next = ++pointer % size; - var trashMark = buffer[next]; - if (trashMark) { - trashMark.clear(); - } - buffer[next] = cm.setBookmark(cursor); - } - if (curMark) { - var markPos = curMark.find(); - // avoid recording redundant cursor position - if (markPos && !cursorEqual(markPos, oldCur)) { - useNextSlot(oldCur); - } - } else { - useNextSlot(oldCur); - } - useNextSlot(newCur); - head = pointer; - tail = pointer - size + 1; - if (tail < 0) { - tail = 0; - } - } - function move(cm, offset) { - pointer += offset; - if (pointer > head) { - pointer = head; - } else if (pointer < tail) { - pointer = tail; - } - var mark = buffer[(size + pointer) % size]; - // skip marks that are temporarily removed from text buffer - if (mark && !mark.find()) { - var inc = offset > 0 ? 1 : -1; - var newCur; - var oldCur = cm.getCursor(); - do { - pointer += inc; - mark = buffer[(size + pointer) % size]; - // skip marks that are the same as current position - if (mark && - (newCur = mark.find()) && - !cursorEqual(oldCur, newCur)) { - break; - } - } while (pointer < head && pointer > tail); - } - return mark; - } - return { - cachedCursor: undefined, //used for # and * jumps - add: add, - move: move - }; - }; - - // Returns an object to track the changes associated insert mode. It - // clones the object that is passed in, or creates an empty object one if - // none is provided. - var createInsertModeChanges = function(c) { - if (c) { - // Copy construction - return { - changes: c.changes, - expectCursorActivityForChange: c.expectCursorActivityForChange - }; - } - return { - // Change list - changes: [], - // Set to true on change, false on cursorActivity. - expectCursorActivityForChange: false - }; - }; - - function MacroModeState() { - this.latestRegister = undefined; - this.isPlaying = false; - this.isRecording = false; - this.replaySearchQueries = []; - this.onRecordingDone = undefined; - this.lastInsertModeChanges = createInsertModeChanges(); - } - MacroModeState.prototype = { - exitMacroRecordMode: function() { - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.onRecordingDone) { - macroModeState.onRecordingDone(); // close dialog - } - macroModeState.onRecordingDone = undefined; - macroModeState.isRecording = false; - }, - enterMacroRecordMode: function(cm, registerName) { - var register = - vimGlobalState.registerController.getRegister(registerName); - if (register) { - register.clear(); - this.latestRegister = registerName; - if (cm.openDialog) { - this.onRecordingDone = cm.openDialog( - '(recording)['+registerName+']', null, {bottom:true}); - } - this.isRecording = true; - } - } - }; - - function maybeInitVimState(cm) { - if (!cm.state.vim) { - // Store instance state in the CodeMirror object. - cm.state.vim = { - inputState: new InputState(), - // Vim's input state that triggered the last edit, used to repeat - // motions and operators with '.'. - lastEditInputState: undefined, - // Vim's action command before the last edit, used to repeat actions - // with '.' and insert mode repeat. - lastEditActionCommand: undefined, - // When using jk for navigation, if you move from a longer line to a - // shorter line, the cursor may clip to the end of the shorter line. - // If j is pressed again and cursor goes to the next line, the - // cursor should go back to its horizontal position on the longer - // line if it can. This is to keep track of the horizontal position. - lastHPos: -1, - // Doing the same with screen-position for gj/gk - lastHSPos: -1, - // The last motion command run. Cleared if a non-motion command gets - // executed in between. - lastMotion: null, - marks: {}, - // Mark for rendering fake cursor for visual mode. - fakeCursor: null, - insertMode: false, - // Repeat count for changes made in insert mode, triggered by key - // sequences like 3,i. Only exists when insertMode is true. - insertModeRepeat: undefined, - visualMode: false, - // If we are in visual line mode. No effect if visualMode is false. - visualLine: false, - visualBlock: false, - lastSelection: null, - lastPastedText: null, - sel: {}, - // Buffer-local/window-local values of vim options. - options: {} - }; - } - return cm.state.vim; - } - var vimGlobalState; - function resetVimGlobalState() { - vimGlobalState = { - // The current search query. - searchQuery: null, - // Whether we are searching backwards. - searchIsReversed: false, - // Replace part of the last substituted pattern - lastSubstituteReplacePart: undefined, - jumpList: createCircularJumpList(), - macroModeState: new MacroModeState, - // Recording latest f, t, F or T motion command. - lastCharacterSearch: {increment:0, forward:true, selectedCharacter:''}, - registerController: new RegisterController({}), - // search history buffer - searchHistoryController: new HistoryController(), - // ex Command history buffer - exCommandHistoryController : new HistoryController() - }; - for (var optionName in options) { - var option = options[optionName]; - option.value = option.defaultValue; - } - } - - var lastInsertModeKeyTimer; - var vimApi= { - buildKeyMap: function() { - // TODO: Convert keymap into dictionary format for fast lookup. - }, - // Testing hook, though it might be useful to expose the register - // controller anyways. - getRegisterController: function() { - return vimGlobalState.registerController; - }, - // Testing hook. - resetVimGlobalState_: resetVimGlobalState, - - // Testing hook. - getVimGlobalState_: function() { - return vimGlobalState; - }, - - // Testing hook. - maybeInitVimState_: maybeInitVimState, - - suppressErrorLogging: false, - - InsertModeKey: InsertModeKey, - map: function(lhs, rhs, ctx) { - // Add user defined key bindings. - exCommandDispatcher.map(lhs, rhs, ctx); - }, - unmap: function(lhs, ctx) { - exCommandDispatcher.unmap(lhs, ctx); - }, - // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace - // them, or somehow make them work with the existing CodeMirror setOption/getOption API. - setOption: setOption, - getOption: getOption, - defineOption: defineOption, - defineEx: function(name, prefix, func){ - if (!prefix) { - prefix = name; - } else if (name.indexOf(prefix) !== 0) { - throw new Error('(Vim.defineEx) "'+prefix+'" is not a prefix of "'+name+'", command not registered'); - } - exCommands[name]=func; - exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; - }, - handleKey: function (cm, key, origin) { - var command = this.findKey(cm, key, origin); - if (typeof command === 'function') { - return command(); - } - }, - /** - * This is the outermost function called by CodeMirror, after keys have - * been mapped to their Vim equivalents. - * - * Finds a command based on the key (and cached keys if there is a - * multi-key sequence). Returns `undefined` if no key is matched, a noop - * function if a partial match is found (multi-key), and a function to - * execute the bound command if a a key is matched. The function always - * returns true. - */ - findKey: function(cm, key, origin) { - var vim = maybeInitVimState(cm); - function handleMacroRecording() { - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.isRecording) { - if (key == 'q') { - macroModeState.exitMacroRecordMode(); - clearInputState(cm); - return true; - } - if (origin != 'mapping') { - logKey(macroModeState, key); - } - } - } - function handleEsc() { - if (key == '') { - // Clear input state and get back to normal mode. - clearInputState(cm); - if (vim.visualMode) { - exitVisualMode(cm); - } else if (vim.insertMode) { - exitInsertMode(cm); - } - return true; - } - } - function doKeyToKey(keys) { - // TODO: prevent infinite recursion. - var match; - while (keys) { - // Pull off one command key, which is either a single character - // or a special sequence wrapped in '<' and '>', e.g. ''. - match = (/<\w+-.+?>|<\w+>|./).exec(keys); - key = match[0]; - keys = keys.substring(match.index + key.length); - CodeMirror.Vim.handleKey(cm, key, 'mapping'); - } - } - - function handleKeyInsertMode() { - if (handleEsc()) { return true; } - var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; - var keysAreChars = key.length == 1; - var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); - // Need to check all key substrings in insert mode. - while (keys.length > 1 && match.type != 'full') { - var keys = vim.inputState.keyBuffer = keys.slice(1); - var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert'); - if (thisMatch.type != 'none') { match = thisMatch; } - } - if (match.type == 'none') { clearInputState(cm); return false; } - else if (match.type == 'partial') { - if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } - lastInsertModeKeyTimer = window.setTimeout( - function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } }, - getOption('insertModeEscKeysTimeout')); - return !keysAreChars; - } - - if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); } - if (keysAreChars) { - var selections = cm.listSelections(); - for (var i = 0; i < selections.length; i++) { - var here = selections[i].head; - cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input'); - } - vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop(); - } - clearInputState(cm); - return match.command; - } - - function handleKeyNonInsertMode() { - if (handleMacroRecording() || handleEsc()) { return true; } - - var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key; - if (/^[1-9]\d*$/.test(keys)) { return true; } - - var keysMatcher = /^(\d*)(.*)$/.exec(keys); - if (!keysMatcher) { clearInputState(cm); return false; } - var context = vim.visualMode ? 'visual' : - 'normal'; - var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context); - if (match.type == 'none') { clearInputState(cm); return false; } - else if (match.type == 'partial') { return true; } - - vim.inputState.keyBuffer = ''; - var keysMatcher = /^(\d*)(.*)$/.exec(keys); - if (keysMatcher[1] && keysMatcher[1] != '0') { - vim.inputState.pushRepeatDigit(keysMatcher[1]); - } - return match.command; - } - - var command; - if (vim.insertMode) { command = handleKeyInsertMode(); } - else { command = handleKeyNonInsertMode(); } - if (command === false) { - return !vim.insertMode && key.length === 1 ? function() { return true; } : undefined; - } else if (command === true) { - // TODO: Look into using CodeMirror's multi-key handling. - // Return no-op since we are caching the key. Counts as handled, but - // don't want act on it just yet. - return function() { return true; }; - } else { - return function() { - return cm.operation(function() { - cm.curOp.isVimOp = true; - try { - if (command.type == 'keyToKey') { - doKeyToKey(command.toKeys); - } else { - commandDispatcher.processCommand(cm, vim, command); - } - } catch (e) { - // clear VIM state in case it's in a bad state. - cm.state.vim = undefined; - maybeInitVimState(cm); - if (!CodeMirror.Vim.suppressErrorLogging) { - console['log'](e); - } - throw e; - } - return true; - }); - }; - } - }, - handleEx: function(cm, input) { - exCommandDispatcher.processCommand(cm, input); - }, - - defineMotion: defineMotion, - defineAction: defineAction, - defineOperator: defineOperator, - mapCommand: mapCommand, - _mapCommand: _mapCommand, - - defineRegister: defineRegister, - - exitVisualMode: exitVisualMode, - exitInsertMode: exitInsertMode - }; - - // Represents the current input state. - function InputState() { - this.prefixRepeat = []; - this.motionRepeat = []; - - this.operator = null; - this.operatorArgs = null; - this.motion = null; - this.motionArgs = null; - this.keyBuffer = []; // For matching multi-key commands. - this.registerName = null; // Defaults to the unnamed register. - } - InputState.prototype.pushRepeatDigit = function(n) { - if (!this.operator) { - this.prefixRepeat = this.prefixRepeat.concat(n); - } else { - this.motionRepeat = this.motionRepeat.concat(n); - } - }; - InputState.prototype.getRepeat = function() { - var repeat = 0; - if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) { - repeat = 1; - if (this.prefixRepeat.length > 0) { - repeat *= parseInt(this.prefixRepeat.join(''), 10); - } - if (this.motionRepeat.length > 0) { - repeat *= parseInt(this.motionRepeat.join(''), 10); - } - } - return repeat; - }; - - function clearInputState(cm, reason) { - cm.state.vim.inputState = new InputState(); - CodeMirror.signal(cm, 'vim-command-done', reason); - } - - /* - * Register stores information about copy and paste registers. Besides - * text, a register must store whether it is linewise (i.e., when it is - * pasted, should it insert itself into a new line, or should the text be - * inserted at the cursor position.) - */ - function Register(text, linewise, blockwise) { - this.clear(); - this.keyBuffer = [text || '']; - this.insertModeChanges = []; - this.searchQueries = []; - this.linewise = !!linewise; - this.blockwise = !!blockwise; - } - Register.prototype = { - setText: function(text, linewise, blockwise) { - this.keyBuffer = [text || '']; - this.linewise = !!linewise; - this.blockwise = !!blockwise; - }, - pushText: function(text, linewise) { - // if this register has ever been set to linewise, use linewise. - if (linewise) { - if (!this.linewise) { - this.keyBuffer.push('\n'); - } - this.linewise = true; - } - this.keyBuffer.push(text); - }, - pushInsertModeChanges: function(changes) { - this.insertModeChanges.push(createInsertModeChanges(changes)); - }, - pushSearchQuery: function(query) { - this.searchQueries.push(query); - }, - clear: function() { - this.keyBuffer = []; - this.insertModeChanges = []; - this.searchQueries = []; - this.linewise = false; - }, - toString: function() { - return this.keyBuffer.join(''); - } - }; - - /** - * Defines an external register. - * - * The name should be a single character that will be used to reference the register. - * The register should support setText, pushText, clear, and toString(). See Register - * for a reference implementation. - */ - function defineRegister(name, register) { - var registers = vimGlobalState.registerController.registers; - if (!name || name.length != 1) { - throw Error('Register name must be 1 character'); - } - if (registers[name]) { - throw Error('Register already defined ' + name); - } - registers[name] = register; - validRegisters.push(name); - } - - /* - * vim registers allow you to keep many independent copy and paste buffers. - * See http://usevim.com/2012/04/13/registers/ for an introduction. - * - * RegisterController keeps the state of all the registers. An initial - * state may be passed in. The unnamed register '"' will always be - * overridden. - */ - function RegisterController(registers) { - this.registers = registers; - this.unnamedRegister = registers['"'] = new Register(); - registers['.'] = new Register(); - registers[':'] = new Register(); - registers['/'] = new Register(); - } - RegisterController.prototype = { - pushText: function(registerName, operator, text, linewise, blockwise) { - if (linewise && text.charAt(text.length - 1) !== '\n'){ - text += '\n'; - } - // Lowercase and uppercase registers refer to the same register. - // Uppercase just means append. - var register = this.isValidRegister(registerName) ? - this.getRegister(registerName) : null; - // if no register/an invalid register was specified, things go to the - // default registers - if (!register) { - switch (operator) { - case 'yank': - // The 0 register contains the text from the most recent yank. - this.registers['0'] = new Register(text, linewise, blockwise); - break; - case 'delete': - case 'change': - if (text.indexOf('\n') == -1) { - // Delete less than 1 line. Update the small delete register. - this.registers['-'] = new Register(text, linewise); - } else { - // Shift down the contents of the numbered registers and put the - // deleted text into register 1. - this.shiftNumericRegisters_(); - this.registers['1'] = new Register(text, linewise); - } - break; - } - // Make sure the unnamed register is set to what just happened - this.unnamedRegister.setText(text, linewise, blockwise); - return; - } - - // If we've gotten to this point, we've actually specified a register - var append = isUpperCase(registerName); - if (append) { - register.pushText(text, linewise); - } else { - register.setText(text, linewise, blockwise); - } - // The unnamed register always has the same value as the last used - // register. - this.unnamedRegister.setText(register.toString(), linewise); - }, - // Gets the register named @name. If one of @name doesn't already exist, - // create it. If @name is invalid, return the unnamedRegister. - getRegister: function(name) { - if (!this.isValidRegister(name)) { - return this.unnamedRegister; - } - name = name.toLowerCase(); - if (!this.registers[name]) { - this.registers[name] = new Register(); - } - return this.registers[name]; - }, - isValidRegister: function(name) { - return name && inArray(name, validRegisters); - }, - shiftNumericRegisters_: function() { - for (var i = 9; i >= 2; i--) { - this.registers[i] = this.getRegister('' + (i - 1)); - } - } - }; - function HistoryController() { - this.historyBuffer = []; - this.iterator = 0; - this.initialPrefix = null; - } - HistoryController.prototype = { - // the input argument here acts a user entered prefix for a small time - // until we start autocompletion in which case it is the autocompleted. - nextMatch: function (input, up) { - var historyBuffer = this.historyBuffer; - var dir = up ? -1 : 1; - if (this.initialPrefix === null) this.initialPrefix = input; - for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) { - var element = historyBuffer[i]; - for (var j = 0; j <= element.length; j++) { - if (this.initialPrefix == element.substring(0, j)) { - this.iterator = i; - return element; - } - } - } - // should return the user input in case we reach the end of buffer. - if (i >= historyBuffer.length) { - this.iterator = historyBuffer.length; - return this.initialPrefix; - } - // return the last autocompleted query or exCommand as it is. - if (i < 0 ) return input; - }, - pushInput: function(input) { - var index = this.historyBuffer.indexOf(input); - if (index > -1) this.historyBuffer.splice(index, 1); - if (input.length) this.historyBuffer.push(input); - }, - reset: function() { - this.initialPrefix = null; - this.iterator = this.historyBuffer.length; - } - }; - var commandDispatcher = { - matchCommand: function(keys, keyMap, inputState, context) { - var matches = commandMatches(keys, keyMap, context, inputState); - if (!matches.full && !matches.partial) { - return {type: 'none'}; - } else if (!matches.full && matches.partial) { - return {type: 'partial'}; - } - - var bestMatch; - for (var i = 0; i < matches.full.length; i++) { - var match = matches.full[i]; - if (!bestMatch) { - bestMatch = match; - } - } - if (bestMatch.keys.slice(-11) == '') { - var character = lastChar(keys); - if (!character) return {type: 'none'}; - inputState.selectedCharacter = character; - } - return {type: 'full', command: bestMatch}; - }, - processCommand: function(cm, vim, command) { - vim.inputState.repeatOverride = command.repeatOverride; - switch (command.type) { - case 'motion': - this.processMotion(cm, vim, command); - break; - case 'operator': - this.processOperator(cm, vim, command); - break; - case 'operatorMotion': - this.processOperatorMotion(cm, vim, command); - break; - case 'action': - this.processAction(cm, vim, command); - break; - case 'search': - this.processSearch(cm, vim, command); - break; - case 'ex': - case 'keyToEx': - this.processEx(cm, vim, command); - break; - default: - break; - } - }, - processMotion: function(cm, vim, command) { - vim.inputState.motion = command.motion; - vim.inputState.motionArgs = copyArgs(command.motionArgs); - this.evalInput(cm, vim); - }, - processOperator: function(cm, vim, command) { - var inputState = vim.inputState; - if (inputState.operator) { - if (inputState.operator == command.operator) { - // Typing an operator twice like 'dd' makes the operator operate - // linewise - inputState.motion = 'expandToLine'; - inputState.motionArgs = { linewise: true }; - this.evalInput(cm, vim); - return; - } else { - // 2 different operators in a row doesn't make sense. - clearInputState(cm); - } - } - inputState.operator = command.operator; - inputState.operatorArgs = copyArgs(command.operatorArgs); - if (vim.visualMode) { - // Operating on a selection in visual mode. We don't need a motion. - this.evalInput(cm, vim); - } - }, - processOperatorMotion: function(cm, vim, command) { - var visualMode = vim.visualMode; - var operatorMotionArgs = copyArgs(command.operatorMotionArgs); - if (operatorMotionArgs) { - // Operator motions may have special behavior in visual mode. - if (visualMode && operatorMotionArgs.visualLine) { - vim.visualLine = true; - } - } - this.processOperator(cm, vim, command); - if (!visualMode) { - this.processMotion(cm, vim, command); - } - }, - processAction: function(cm, vim, command) { - var inputState = vim.inputState; - var repeat = inputState.getRepeat(); - var repeatIsExplicit = !!repeat; - var actionArgs = copyArgs(command.actionArgs) || {}; - if (inputState.selectedCharacter) { - actionArgs.selectedCharacter = inputState.selectedCharacter; - } - // Actions may or may not have motions and operators. Do these first. - if (command.operator) { - this.processOperator(cm, vim, command); - } - if (command.motion) { - this.processMotion(cm, vim, command); - } - if (command.motion || command.operator) { - this.evalInput(cm, vim); - } - actionArgs.repeat = repeat || 1; - actionArgs.repeatIsExplicit = repeatIsExplicit; - actionArgs.registerName = inputState.registerName; - clearInputState(cm); - vim.lastMotion = null; - if (command.isEdit) { - this.recordLastEdit(vim, inputState, command); - } - actions[command.action](cm, actionArgs, vim); - }, - processSearch: function(cm, vim, command) { - if (!cm.getSearchCursor) { - // Search depends on SearchCursor. - return; - } - var forward = command.searchArgs.forward; - var wholeWordOnly = command.searchArgs.wholeWordOnly; - getSearchState(cm).setReversed(!forward); - var promptPrefix = (forward) ? '/' : '?'; - var originalQuery = getSearchState(cm).getQuery(); - var originalScrollPos = cm.getScrollInfo(); - function handleQuery(query, ignoreCase, smartCase) { - vimGlobalState.searchHistoryController.pushInput(query); - vimGlobalState.searchHistoryController.reset(); - try { - updateSearchQuery(cm, query, ignoreCase, smartCase); - } catch (e) { - showConfirm(cm, 'Invalid regex: ' + query); - clearInputState(cm); - return; - } - commandDispatcher.processMotion(cm, vim, { - type: 'motion', - motion: 'findNext', - motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } - }); - } - function onPromptClose(query) { - cm.scrollTo(originalScrollPos.left, originalScrollPos.top); - handleQuery(query, true /** ignoreCase */, true /** smartCase */); - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.isRecording) { - logSearchQuery(macroModeState, query); - } - } - function onPromptKeyUp(e, query, close) { - var keyName = CodeMirror.keyName(e), up, offset; - if (keyName == 'Up' || keyName == 'Down') { - up = keyName == 'Up' ? true : false; - offset = e.target ? e.target.selectionEnd : 0; - query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; - close(query); - if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); - } else { - if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') - vimGlobalState.searchHistoryController.reset(); - } - var parsedQuery; - try { - parsedQuery = updateSearchQuery(cm, query, - true /** ignoreCase */, true /** smartCase */); - } catch (e) { - // Swallow bad regexes for incremental search. - } - if (parsedQuery) { - cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); - } else { - clearSearchHighlight(cm); - cm.scrollTo(originalScrollPos.left, originalScrollPos.top); - } - } - function onPromptKeyDown(e, query, close) { - var keyName = CodeMirror.keyName(e); - if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || - (keyName == 'Backspace' && query == '')) { - vimGlobalState.searchHistoryController.pushInput(query); - vimGlobalState.searchHistoryController.reset(); - updateSearchQuery(cm, originalQuery); - clearSearchHighlight(cm); - cm.scrollTo(originalScrollPos.left, originalScrollPos.top); - CodeMirror.e_stop(e); - clearInputState(cm); - close(); - cm.focus(); - } else if (keyName == 'Up' || keyName == 'Down') { - CodeMirror.e_stop(e); - } else if (keyName == 'Ctrl-U') { - // Ctrl-U clears input. - CodeMirror.e_stop(e); - close(''); - } - } - switch (command.searchArgs.querySrc) { - case 'prompt': - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.isPlaying) { - var query = macroModeState.replaySearchQueries.shift(); - handleQuery(query, true /** ignoreCase */, false /** smartCase */); - } else { - showPrompt(cm, { - onClose: onPromptClose, - prefix: promptPrefix, - desc: searchPromptDesc, - onKeyUp: onPromptKeyUp, - onKeyDown: onPromptKeyDown - }); - } - break; - case 'wordUnderCursor': - var word = expandWordUnderCursor(cm, false /** inclusive */, - true /** forward */, false /** bigWord */, - true /** noSymbol */); - var isKeyword = true; - if (!word) { - word = expandWordUnderCursor(cm, false /** inclusive */, - true /** forward */, false /** bigWord */, - false /** noSymbol */); - isKeyword = false; - } - if (!word) { - return; - } - var query = cm.getLine(word.start.line).substring(word.start.ch, - word.end.ch); - if (isKeyword && wholeWordOnly) { - query = '\\b' + query + '\\b'; - } else { - query = escapeRegex(query); - } - - // cachedCursor is used to save the old position of the cursor - // when * or # causes vim to seek for the nearest word and shift - // the cursor before entering the motion. - vimGlobalState.jumpList.cachedCursor = cm.getCursor(); - cm.setCursor(word.start); - - handleQuery(query, true /** ignoreCase */, false /** smartCase */); - break; - } - }, - processEx: function(cm, vim, command) { - function onPromptClose(input) { - // Give the prompt some time to close so that if processCommand shows - // an error, the elements don't overlap. - vimGlobalState.exCommandHistoryController.pushInput(input); - vimGlobalState.exCommandHistoryController.reset(); - exCommandDispatcher.processCommand(cm, input); - } - function onPromptKeyDown(e, input, close) { - var keyName = CodeMirror.keyName(e), up, offset; - if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || - (keyName == 'Backspace' && input == '')) { - vimGlobalState.exCommandHistoryController.pushInput(input); - vimGlobalState.exCommandHistoryController.reset(); - CodeMirror.e_stop(e); - clearInputState(cm); - close(); - cm.focus(); - } - if (keyName == 'Up' || keyName == 'Down') { - CodeMirror.e_stop(e); - up = keyName == 'Up' ? true : false; - offset = e.target ? e.target.selectionEnd : 0; - input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; - close(input); - if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); - } else if (keyName == 'Ctrl-U') { - // Ctrl-U clears input. - CodeMirror.e_stop(e); - close(''); - } else { - if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') - vimGlobalState.exCommandHistoryController.reset(); - } - } - if (command.type == 'keyToEx') { - // Handle user defined Ex to Ex mappings - exCommandDispatcher.processCommand(cm, command.exArgs.input); - } else { - if (vim.visualMode) { - showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', - onKeyDown: onPromptKeyDown, selectValueOnOpen: false}); - } else { - showPrompt(cm, { onClose: onPromptClose, prefix: ':', - onKeyDown: onPromptKeyDown}); - } - } - }, - evalInput: function(cm, vim) { - // If the motion command is set, execute both the operator and motion. - // Otherwise return. - var inputState = vim.inputState; - var motion = inputState.motion; - var motionArgs = inputState.motionArgs || {}; - var operator = inputState.operator; - var operatorArgs = inputState.operatorArgs || {}; - var registerName = inputState.registerName; - var sel = vim.sel; - // TODO: Make sure cm and vim selections are identical outside visual mode. - var origHead = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.head): cm.getCursor('head')); - var origAnchor = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor('anchor')); - var oldHead = copyCursor(origHead); - var oldAnchor = copyCursor(origAnchor); - var newHead, newAnchor; - var repeat; - if (operator) { - this.recordLastEdit(vim, inputState); - } - if (inputState.repeatOverride !== undefined) { - // If repeatOverride is specified, that takes precedence over the - // input state's repeat. Used by Ex mode and can be user defined. - repeat = inputState.repeatOverride; - } else { - repeat = inputState.getRepeat(); - } - if (repeat > 0 && motionArgs.explicitRepeat) { - motionArgs.repeatIsExplicit = true; - } else if (motionArgs.noRepeat || - (!motionArgs.explicitRepeat && repeat === 0)) { - repeat = 1; - motionArgs.repeatIsExplicit = false; - } - if (inputState.selectedCharacter) { - // If there is a character input, stick it in all of the arg arrays. - motionArgs.selectedCharacter = operatorArgs.selectedCharacter = - inputState.selectedCharacter; - } - motionArgs.repeat = repeat; - clearInputState(cm); - if (motion) { - var motionResult = motions[motion](cm, origHead, motionArgs, vim); - vim.lastMotion = motions[motion]; - if (!motionResult) { - return; - } - if (motionArgs.toJumplist) { - var jumpList = vimGlobalState.jumpList; - // if the current motion is # or *, use cachedCursor - var cachedCursor = jumpList.cachedCursor; - if (cachedCursor) { - recordJumpPosition(cm, cachedCursor, motionResult); - delete jumpList.cachedCursor; - } else { - recordJumpPosition(cm, origHead, motionResult); - } - } - if (motionResult instanceof Array) { - newAnchor = motionResult[0]; - newHead = motionResult[1]; - } else { - newHead = motionResult; - } - // TODO: Handle null returns from motion commands better. - if (!newHead) { - newHead = copyCursor(origHead); - } - if (vim.visualMode) { - if (!(vim.visualBlock && newHead.ch === Infinity)) { - newHead = clipCursorToContent(cm, newHead, vim.visualBlock); - } - if (newAnchor) { - newAnchor = clipCursorToContent(cm, newAnchor, true); - } - newAnchor = newAnchor || oldAnchor; - sel.anchor = newAnchor; - sel.head = newHead; - updateCmSelection(cm); - updateMark(cm, vim, '<', - cursorIsBefore(newAnchor, newHead) ? newAnchor - : newHead); - updateMark(cm, vim, '>', - cursorIsBefore(newAnchor, newHead) ? newHead - : newAnchor); - } else if (!operator) { - newHead = clipCursorToContent(cm, newHead); - cm.setCursor(newHead.line, newHead.ch); - } - } - if (operator) { - if (operatorArgs.lastSel) { - // Replaying a visual mode operation - newAnchor = oldAnchor; - var lastSel = operatorArgs.lastSel; - var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line); - var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch); - if (lastSel.visualLine) { - // Linewise Visual mode: The same number of lines. - newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); - } else if (lastSel.visualBlock) { - // Blockwise Visual mode: The same number of lines and columns. - newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset); - } else if (lastSel.head.line == lastSel.anchor.line) { - // Normal Visual mode within one line: The same number of characters. - newHead = Pos(oldAnchor.line, oldAnchor.ch + chOffset); - } else { - // Normal Visual mode with several lines: The same number of lines, in the - // last line the same number of characters as in the last line the last time. - newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch); - } - vim.visualMode = true; - vim.visualLine = lastSel.visualLine; - vim.visualBlock = lastSel.visualBlock; - sel = vim.sel = { - anchor: newAnchor, - head: newHead - }; - updateCmSelection(cm); - } else if (vim.visualMode) { - operatorArgs.lastSel = { - anchor: copyCursor(sel.anchor), - head: copyCursor(sel.head), - visualBlock: vim.visualBlock, - visualLine: vim.visualLine - }; - } - var curStart, curEnd, linewise, mode; - var cmSel; - if (vim.visualMode) { - // Init visual op - curStart = cursorMin(sel.head, sel.anchor); - curEnd = cursorMax(sel.head, sel.anchor); - linewise = vim.visualLine || operatorArgs.linewise; - mode = vim.visualBlock ? 'block' : - linewise ? 'line' : - 'char'; - cmSel = makeCmSelection(cm, { - anchor: curStart, - head: curEnd - }, mode); - if (linewise) { - var ranges = cmSel.ranges; - if (mode == 'block') { - // Linewise operators in visual block mode extend to end of line - for (var i = 0; i < ranges.length; i++) { - ranges[i].head.ch = lineLength(cm, ranges[i].head.line); - } - } else if (mode == 'line') { - ranges[0].head = Pos(ranges[0].head.line + 1, 0); - } - } - } else { - // Init motion op - curStart = copyCursor(newAnchor || oldAnchor); - curEnd = copyCursor(newHead || oldHead); - if (cursorIsBefore(curEnd, curStart)) { - var tmp = curStart; - curStart = curEnd; - curEnd = tmp; - } - linewise = motionArgs.linewise || operatorArgs.linewise; - if (linewise) { - // Expand selection to entire line. - expandSelectionToLine(cm, curStart, curEnd); - } else if (motionArgs.forward) { - // Clip to trailing newlines only if the motion goes forward. - clipToLine(cm, curStart, curEnd); - } - mode = 'char'; - var exclusive = !motionArgs.inclusive || linewise; - cmSel = makeCmSelection(cm, { - anchor: curStart, - head: curEnd - }, mode, exclusive); - } - cm.setSelections(cmSel.ranges, cmSel.primary); - vim.lastMotion = null; - operatorArgs.repeat = repeat; // For indent in visual mode. - operatorArgs.registerName = registerName; - // Keep track of linewise as it affects how paste and change behave. - operatorArgs.linewise = linewise; - var operatorMoveTo = operators[operator]( - cm, operatorArgs, cmSel.ranges, oldAnchor, newHead); - if (vim.visualMode) { - exitVisualMode(cm, operatorMoveTo != null); - } - if (operatorMoveTo) { - cm.setCursor(operatorMoveTo); - } - } - }, - recordLastEdit: function(vim, inputState, actionCommand) { - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.isPlaying) { return; } - vim.lastEditInputState = inputState; - vim.lastEditActionCommand = actionCommand; - macroModeState.lastInsertModeChanges.changes = []; - macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false; - } - }; - - /** - * typedef {Object{line:number,ch:number}} Cursor An object containing the - * position of the cursor. - */ - // All of the functions below return Cursor objects. - var motions = { - moveToTopLine: function(cm, _head, motionArgs) { - var line = getUserVisibleLines(cm).top + motionArgs.repeat -1; - return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); - }, - moveToMiddleLine: function(cm) { - var range = getUserVisibleLines(cm); - var line = Math.floor((range.top + range.bottom) * 0.5); - return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); - }, - moveToBottomLine: function(cm, _head, motionArgs) { - var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1; - return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line))); - }, - expandToLine: function(_cm, head, motionArgs) { - // Expands forward to end of line, and then to next line if repeat is - // >1. Does not handle backward motion! - var cur = head; - return Pos(cur.line + motionArgs.repeat - 1, Infinity); - }, - findNext: function(cm, _head, motionArgs) { - var state = getSearchState(cm); - var query = state.getQuery(); - if (!query) { - return; - } - var prev = !motionArgs.forward; - // If search is initiated with ? instead of /, negate direction. - prev = (state.isReversed()) ? !prev : prev; - highlightSearchMatches(cm, query); - return findNext(cm, prev/** prev */, query, motionArgs.repeat); - }, - goToMark: function(cm, _head, motionArgs, vim) { - var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter); - if (pos) { - return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos; - } - return null; - }, - moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim) { - if (vim.visualBlock && motionArgs.sameLine) { - var sel = vim.sel; - return [ - clipCursorToContent(cm, Pos(sel.anchor.line, sel.head.ch)), - clipCursorToContent(cm, Pos(sel.head.line, sel.anchor.ch)) - ]; - } else { - return ([vim.sel.head, vim.sel.anchor]); - } - }, - jumpToMark: function(cm, head, motionArgs, vim) { - var best = head; - for (var i = 0; i < motionArgs.repeat; i++) { - var cursor = best; - for (var key in vim.marks) { - if (!isLowerCase(key)) { - continue; - } - var mark = vim.marks[key].find(); - var isWrongDirection = (motionArgs.forward) ? - cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark); - - if (isWrongDirection) { - continue; - } - if (motionArgs.linewise && (mark.line == cursor.line)) { - continue; - } - - var equal = cursorEqual(cursor, best); - var between = (motionArgs.forward) ? - cursorIsBetween(cursor, mark, best) : - cursorIsBetween(best, mark, cursor); - - if (equal || between) { - best = mark; - } - } - } - - if (motionArgs.linewise) { - // Vim places the cursor on the first non-whitespace character of - // the line if there is one, else it places the cursor at the end - // of the line, regardless of whether a mark was found. - best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line))); - } - return best; - }, - moveByCharacters: function(_cm, head, motionArgs) { - var cur = head; - var repeat = motionArgs.repeat; - var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat; - return Pos(cur.line, ch); - }, - moveByLines: function(cm, head, motionArgs, vim) { - var cur = head; - var endCh = cur.ch; - // Depending what our last motion was, we may want to do different - // things. If our last motion was moving vertically, we want to - // preserve the HPos from our last horizontal move. If our last motion - // was going to the end of a line, moving vertically we should go to - // the end of the line, etc. - switch (vim.lastMotion) { - case this.moveByLines: - case this.moveByDisplayLines: - case this.moveByScroll: - case this.moveToColumn: - case this.moveToEol: - endCh = vim.lastHPos; - break; - default: - vim.lastHPos = endCh; - } - var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0); - var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; - var first = cm.firstLine(); - var last = cm.lastLine(); - // Vim go to line begin or line end when cursor at first/last line and - // move to previous/next line is triggered. - if (line < first && cur.line == first){ - return this.moveToStartOfLine(cm, head, motionArgs, vim); - }else if (line > last && cur.line == last){ - return this.moveToEol(cm, head, motionArgs, vim); - } - if (motionArgs.toFirstChar){ - endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); - vim.lastHPos = endCh; - } - vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left; - return Pos(line, endCh); - }, - moveByDisplayLines: function(cm, head, motionArgs, vim) { - var cur = head; - switch (vim.lastMotion) { - case this.moveByDisplayLines: - case this.moveByScroll: - case this.moveByLines: - case this.moveToColumn: - case this.moveToEol: - break; - default: - vim.lastHSPos = cm.charCoords(cur,'div').left; - } - var repeat = motionArgs.repeat; - var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos); - if (res.hitSide) { - if (motionArgs.forward) { - var lastCharCoords = cm.charCoords(res, 'div'); - var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos }; - var res = cm.coordsChar(goalCoords, 'div'); - } else { - var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div'); - resCoords.left = vim.lastHSPos; - res = cm.coordsChar(resCoords, 'div'); - } - } - vim.lastHPos = res.ch; - return res; - }, - moveByPage: function(cm, head, motionArgs) { - // CodeMirror only exposes functions that move the cursor page down, so - // doing this bad hack to move the cursor and move it back. evalInput - // will move the cursor to where it should be in the end. - var curStart = head; - var repeat = motionArgs.repeat; - return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); - }, - moveByParagraph: function(cm, head, motionArgs) { - var dir = motionArgs.forward ? 1 : -1; - return findParagraph(cm, head, motionArgs.repeat, dir); - }, - moveBySentence: function(cm, head, motionArgs) { - var dir = motionArgs.forward ? 1 : -1; - return findSentence(cm, head, motionArgs.repeat, dir); - }, - moveByScroll: function(cm, head, motionArgs, vim) { - var scrollbox = cm.getScrollInfo(); - var curEnd = null; - var repeat = motionArgs.repeat; - if (!repeat) { - repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); - } - var orig = cm.charCoords(head, 'local'); - motionArgs.repeat = repeat; - var curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim); - if (!curEnd) { - return null; - } - var dest = cm.charCoords(curEnd, 'local'); - cm.scrollTo(null, scrollbox.top + dest.top - orig.top); - return curEnd; - }, - moveByWords: function(cm, head, motionArgs) { - return moveToWord(cm, head, motionArgs.repeat, !!motionArgs.forward, - !!motionArgs.wordEnd, !!motionArgs.bigWord); - }, - moveTillCharacter: function(cm, _head, motionArgs) { - var repeat = motionArgs.repeat; - var curEnd = moveToCharacter(cm, repeat, motionArgs.forward, - motionArgs.selectedCharacter); - var increment = motionArgs.forward ? -1 : 1; - recordLastCharacterSearch(increment, motionArgs); - if (!curEnd) return null; - curEnd.ch += increment; - return curEnd; - }, - moveToCharacter: function(cm, head, motionArgs) { - var repeat = motionArgs.repeat; - recordLastCharacterSearch(0, motionArgs); - return moveToCharacter(cm, repeat, motionArgs.forward, - motionArgs.selectedCharacter) || head; - }, - moveToSymbol: function(cm, head, motionArgs) { - var repeat = motionArgs.repeat; - return findSymbol(cm, repeat, motionArgs.forward, - motionArgs.selectedCharacter) || head; - }, - moveToColumn: function(cm, head, motionArgs, vim) { - var repeat = motionArgs.repeat; - // repeat is equivalent to which column we want to move to! - vim.lastHPos = repeat - 1; - vim.lastHSPos = cm.charCoords(head,'div').left; - return moveToColumn(cm, repeat); - }, - moveToEol: function(cm, head, motionArgs, vim) { - var cur = head; - vim.lastHPos = Infinity; - var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); - var end=cm.clipPos(retval); - end.ch--; - vim.lastHSPos = cm.charCoords(end,'div').left; - return retval; - }, - moveToFirstNonWhiteSpaceCharacter: function(cm, head) { - // Go to the start of the line where the text begins, or the end for - // whitespace-only lines - var cursor = head; - return Pos(cursor.line, - findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line))); - }, - moveToMatchedSymbol: function(cm, head) { - var cursor = head; - var line = cursor.line; - var ch = cursor.ch; - var lineText = cm.getLine(line); - var symbol; - for (; ch < lineText.length; ch++) { - symbol = lineText.charAt(ch); - if (symbol && isMatchableSymbol(symbol)) { - var style = cm.getTokenTypeAt(Pos(line, ch + 1)); - if (style !== "string" && style !== "comment") { - break; - } - } - } - if (ch < lineText.length) { - var matched = cm.findMatchingBracket(Pos(line, ch)); - return matched.to; - } else { - return cursor; - } - }, - moveToStartOfLine: function(_cm, head) { - return Pos(head.line, 0); - }, - moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) { - var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); - if (motionArgs.repeatIsExplicit) { - lineNum = motionArgs.repeat - cm.getOption('firstLineNumber'); - } - return Pos(lineNum, - findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum))); - }, - textObjectManipulation: function(cm, head, motionArgs, vim) { - // TODO: lots of possible exceptions that can be thrown here. Try da( - // outside of a () block. - - // TODO: adding <> >< to this map doesn't work, presumably because - // they're operators - var mirroredPairs = {'(': ')', ')': '(', - '{': '}', '}': '{', - '[': ']', ']': '['}; - var selfPaired = {'\'': true, '"': true}; - - var character = motionArgs.selectedCharacter; - // 'b' refers to '()' block. - // 'B' refers to '{}' block. - if (character == 'b') { - character = '('; - } else if (character == 'B') { - character = '{'; - } - - // Inclusive is the difference between a and i - // TODO: Instead of using the additional text object map to perform text - // object operations, merge the map into the defaultKeyMap and use - // motionArgs to define behavior. Define separate entries for 'aw', - // 'iw', 'a[', 'i[', etc. - var inclusive = !motionArgs.textObjectInner; - - var tmp; - if (mirroredPairs[character]) { - tmp = selectCompanionObject(cm, head, character, inclusive); - } else if (selfPaired[character]) { - tmp = findBeginningAndEnd(cm, head, character, inclusive); - } else if (character === 'W') { - tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, - true /** bigWord */); - } else if (character === 'w') { - tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, - false /** bigWord */); - } else if (character === 'p') { - tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); - motionArgs.linewise = true; - if (vim.visualMode) { - if (!vim.visualLine) { vim.visualLine = true; } - } else { - var operatorArgs = vim.inputState.operatorArgs; - if (operatorArgs) { operatorArgs.linewise = true; } - tmp.end.line--; - } - } else { - // No text object defined for this, don't move. - return null; - } - - if (!cm.state.vim.visualMode) { - return [tmp.start, tmp.end]; - } else { - return expandSelection(cm, tmp.start, tmp.end); - } - }, - - repeatLastCharacterSearch: function(cm, head, motionArgs) { - var lastSearch = vimGlobalState.lastCharacterSearch; - var repeat = motionArgs.repeat; - var forward = motionArgs.forward === lastSearch.forward; - var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); - cm.moveH(-increment, 'char'); - motionArgs.inclusive = forward ? true : false; - var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); - if (!curEnd) { - cm.moveH(increment, 'char'); - return head; - } - curEnd.ch += increment; - return curEnd; - } - }; - - function defineMotion(name, fn) { - motions[name] = fn; - } - - function fillArray(val, times) { - var arr = []; - for (var i = 0; i < times; i++) { - arr.push(val); - } - return arr; - } - /** - * An operator acts on a text selection. It receives the list of selections - * as input. The corresponding CodeMirror selection is guaranteed to - * match the input selection. - */ - var operators = { - change: function(cm, args, ranges) { - var finalHead, text; - var vim = cm.state.vim; - vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock = vim.visualBlock; - if (!vim.visualMode) { - var anchor = ranges[0].anchor, - head = ranges[0].head; - text = cm.getRange(anchor, head); - var lastState = vim.lastEditInputState || {}; - if (lastState.motion == "moveByWords" && !isWhiteSpaceString(text)) { - // Exclude trailing whitespace if the range is not all whitespace. - var match = (/\s+$/).exec(text); - if (match && lastState.motionArgs && lastState.motionArgs.forward) { - head = offsetCursor(head, 0, - match[0].length); - text = text.slice(0, - match[0].length); - } - } - var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE); - var wasLastLine = cm.firstLine() == cm.lastLine(); - if (head.line > cm.lastLine() && args.linewise && !wasLastLine) { - cm.replaceRange('', prevLineEnd, head); - } else { - cm.replaceRange('', anchor, head); - } - if (args.linewise) { - // Push the next line back down, if there is a next line. - if (!wasLastLine) { - cm.setCursor(prevLineEnd); - CodeMirror.commands.newlineAndIndent(cm); - } - // make sure cursor ends up at the end of the line. - anchor.ch = Number.MAX_VALUE; - } - finalHead = anchor; - } else { - text = cm.getSelection(); - var replacement = fillArray('', ranges.length); - cm.replaceSelections(replacement); - finalHead = cursorMin(ranges[0].head, ranges[0].anchor); - } - vimGlobalState.registerController.pushText( - args.registerName, 'change', text, - args.linewise, ranges.length > 1); - actions.enterInsertMode(cm, {head: finalHead}, cm.state.vim); - }, - // delete is a javascript keyword. - 'delete': function(cm, args, ranges) { - var finalHead, text; - var vim = cm.state.vim; - if (!vim.visualBlock) { - var anchor = ranges[0].anchor, - head = ranges[0].head; - if (args.linewise && - head.line != cm.firstLine() && - anchor.line == cm.lastLine() && - anchor.line == head.line - 1) { - // Special case for dd on last line (and first line). - if (anchor.line == cm.firstLine()) { - anchor.ch = 0; - } else { - anchor = Pos(anchor.line - 1, lineLength(cm, anchor.line - 1)); - } - } - text = cm.getRange(anchor, head); - cm.replaceRange('', anchor, head); - finalHead = anchor; - if (args.linewise) { - finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor); - } - } else { - text = cm.getSelection(); - var replacement = fillArray('', ranges.length); - cm.replaceSelections(replacement); - finalHead = ranges[0].anchor; - } - vimGlobalState.registerController.pushText( - args.registerName, 'delete', text, - args.linewise, vim.visualBlock); - var includeLineBreak = vim.insertMode - return clipCursorToContent(cm, finalHead, includeLineBreak); - }, - indent: function(cm, args, ranges) { - var vim = cm.state.vim; - var startLine = ranges[0].anchor.line; - var endLine = vim.visualBlock ? - ranges[ranges.length - 1].anchor.line : - ranges[0].head.line; - // In visual mode, n> shifts the selection right n times, instead of - // shifting n lines right once. - var repeat = (vim.visualMode) ? args.repeat : 1; - if (args.linewise) { - // The only way to delete a newline is to delete until the start of - // the next line, so in linewise mode evalInput will include the next - // line. We don't want this in indent, so we go back a line. - endLine--; - } - for (var i = startLine; i <= endLine; i++) { - for (var j = 0; j < repeat; j++) { - cm.indentLine(i, args.indentRight); - } - } - return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor); - }, - changeCase: function(cm, args, ranges, oldAnchor, newHead) { - var selections = cm.getSelections(); - var swapped = []; - var toLower = args.toLower; - for (var j = 0; j < selections.length; j++) { - var toSwap = selections[j]; - var text = ''; - if (toLower === true) { - text = toSwap.toLowerCase(); - } else if (toLower === false) { - text = toSwap.toUpperCase(); - } else { - for (var i = 0; i < toSwap.length; i++) { - var character = toSwap.charAt(i); - text += isUpperCase(character) ? character.toLowerCase() : - character.toUpperCase(); - } - } - swapped.push(text); - } - cm.replaceSelections(swapped); - if (args.shouldMoveCursor){ - return newHead; - } else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) { - return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor); - } else if (args.linewise){ - return oldAnchor; - } else { - return cursorMin(ranges[0].anchor, ranges[0].head); - } - }, - yank: function(cm, args, ranges, oldAnchor) { - var vim = cm.state.vim; - var text = cm.getSelection(); - var endPos = vim.visualMode - ? cursorMin(vim.sel.anchor, vim.sel.head, ranges[0].head, ranges[0].anchor) - : oldAnchor; - vimGlobalState.registerController.pushText( - args.registerName, 'yank', - text, args.linewise, vim.visualBlock); - return endPos; - } - }; - - function defineOperator(name, fn) { - operators[name] = fn; - } - - var actions = { - jumpListWalk: function(cm, actionArgs, vim) { - if (vim.visualMode) { - return; - } - var repeat = actionArgs.repeat; - var forward = actionArgs.forward; - var jumpList = vimGlobalState.jumpList; - - var mark = jumpList.move(cm, forward ? repeat : -repeat); - var markPos = mark ? mark.find() : undefined; - markPos = markPos ? markPos : cm.getCursor(); - cm.setCursor(markPos); - }, - scroll: function(cm, actionArgs, vim) { - if (vim.visualMode) { - return; - } - var repeat = actionArgs.repeat || 1; - var lineHeight = cm.defaultTextHeight(); - var top = cm.getScrollInfo().top; - var delta = lineHeight * repeat; - var newPos = actionArgs.forward ? top + delta : top - delta; - var cursor = copyCursor(cm.getCursor()); - var cursorCoords = cm.charCoords(cursor, 'local'); - if (actionArgs.forward) { - if (newPos > cursorCoords.top) { - cursor.line += (newPos - cursorCoords.top) / lineHeight; - cursor.line = Math.ceil(cursor.line); - cm.setCursor(cursor); - cursorCoords = cm.charCoords(cursor, 'local'); - cm.scrollTo(null, cursorCoords.top); - } else { - // Cursor stays within bounds. Just reposition the scroll window. - cm.scrollTo(null, newPos); - } - } else { - var newBottom = newPos + cm.getScrollInfo().clientHeight; - if (newBottom < cursorCoords.bottom) { - cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight; - cursor.line = Math.floor(cursor.line); - cm.setCursor(cursor); - cursorCoords = cm.charCoords(cursor, 'local'); - cm.scrollTo( - null, cursorCoords.bottom - cm.getScrollInfo().clientHeight); - } else { - // Cursor stays within bounds. Just reposition the scroll window. - cm.scrollTo(null, newPos); - } - } - }, - scrollToCursor: function(cm, actionArgs) { - var lineNum = cm.getCursor().line; - var charCoords = cm.charCoords(Pos(lineNum, 0), 'local'); - var height = cm.getScrollInfo().clientHeight; - var y = charCoords.top; - var lineHeight = charCoords.bottom - y; - switch (actionArgs.position) { - case 'center': y = y - (height / 2) + lineHeight; - break; - case 'bottom': y = y - height + lineHeight; - break; - } - cm.scrollTo(null, y); - }, - replayMacro: function(cm, actionArgs, vim) { - var registerName = actionArgs.selectedCharacter; - var repeat = actionArgs.repeat; - var macroModeState = vimGlobalState.macroModeState; - if (registerName == '@') { - registerName = macroModeState.latestRegister; - } - while(repeat--){ - executeMacroRegister(cm, vim, macroModeState, registerName); - } - }, - enterMacroRecordMode: function(cm, actionArgs) { - var macroModeState = vimGlobalState.macroModeState; - var registerName = actionArgs.selectedCharacter; - if (vimGlobalState.registerController.isValidRegister(registerName)) { - macroModeState.enterMacroRecordMode(cm, registerName); - } - }, - toggleOverwrite: function(cm) { - if (!cm.state.overwrite) { - cm.toggleOverwrite(true); - cm.setOption('keyMap', 'vim-replace'); - CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); - } else { - cm.toggleOverwrite(false); - cm.setOption('keyMap', 'vim-insert'); - CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); - } - }, - enterInsertMode: function(cm, actionArgs, vim) { - if (cm.getOption('readOnly')) { return; } - vim.insertMode = true; - vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1; - var insertAt = (actionArgs) ? actionArgs.insertAt : null; - var sel = vim.sel; - var head = actionArgs.head || cm.getCursor('head'); - var height = cm.listSelections().length; - if (insertAt == 'eol') { - head = Pos(head.line, lineLength(cm, head.line)); - } else if (insertAt == 'charAfter') { - head = offsetCursor(head, 0, 1); - } else if (insertAt == 'firstNonBlank') { - head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head); - } else if (insertAt == 'startOfSelectedArea') { - if (!vim.visualBlock) { - if (sel.head.line < sel.anchor.line) { - head = sel.head; - } else { - head = Pos(sel.anchor.line, 0); - } - } else { - head = Pos( - Math.min(sel.head.line, sel.anchor.line), - Math.min(sel.head.ch, sel.anchor.ch)); - height = Math.abs(sel.head.line - sel.anchor.line) + 1; - } - } else if (insertAt == 'endOfSelectedArea') { - if (!vim.visualBlock) { - if (sel.head.line >= sel.anchor.line) { - head = offsetCursor(sel.head, 0, 1); - } else { - head = Pos(sel.anchor.line, 0); - } - } else { - head = Pos( - Math.min(sel.head.line, sel.anchor.line), - Math.max(sel.head.ch + 1, sel.anchor.ch)); - height = Math.abs(sel.head.line - sel.anchor.line) + 1; - } - } else if (insertAt == 'inplace') { - if (vim.visualMode){ - return; - } - } - cm.setOption('disableInput', false); - if (actionArgs && actionArgs.replace) { - // Handle Replace-mode as a special case of insert mode. - cm.toggleOverwrite(true); - cm.setOption('keyMap', 'vim-replace'); - CodeMirror.signal(cm, "vim-mode-change", {mode: "replace"}); - } else { - cm.toggleOverwrite(false); - cm.setOption('keyMap', 'vim-insert'); - CodeMirror.signal(cm, "vim-mode-change", {mode: "insert"}); - } - if (!vimGlobalState.macroModeState.isPlaying) { - // Only record if not replaying. - cm.on('change', onChange); - CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); - } - if (vim.visualMode) { - exitVisualMode(cm); - } - selectForInsert(cm, head, height); - }, - toggleVisualMode: function(cm, actionArgs, vim) { - var repeat = actionArgs.repeat; - var anchor = cm.getCursor(); - var head; - // TODO: The repeat should actually select number of characters/lines - // equal to the repeat times the size of the previous visual - // operation. - if (!vim.visualMode) { - // Entering visual mode - vim.visualMode = true; - vim.visualLine = !!actionArgs.linewise; - vim.visualBlock = !!actionArgs.blockwise; - head = clipCursorToContent( - cm, Pos(anchor.line, anchor.ch + repeat - 1), - true /** includeLineBreak */); - vim.sel = { - anchor: anchor, - head: head - }; - CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); - updateCmSelection(cm); - updateMark(cm, vim, '<', cursorMin(anchor, head)); - updateMark(cm, vim, '>', cursorMax(anchor, head)); - } else if (vim.visualLine ^ actionArgs.linewise || - vim.visualBlock ^ actionArgs.blockwise) { - // Toggling between modes - vim.visualLine = !!actionArgs.linewise; - vim.visualBlock = !!actionArgs.blockwise; - CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : ""}); - updateCmSelection(cm); - } else { - exitVisualMode(cm); - } - }, - reselectLastSelection: function(cm, _actionArgs, vim) { - var lastSelection = vim.lastSelection; - if (vim.visualMode) { - updateLastSelection(cm, vim); - } - if (lastSelection) { - var anchor = lastSelection.anchorMark.find(); - var head = lastSelection.headMark.find(); - if (!anchor || !head) { - // If the marks have been destroyed due to edits, do nothing. - return; - } - vim.sel = { - anchor: anchor, - head: head - }; - vim.visualMode = true; - vim.visualLine = lastSelection.visualLine; - vim.visualBlock = lastSelection.visualBlock; - updateCmSelection(cm); - updateMark(cm, vim, '<', cursorMin(anchor, head)); - updateMark(cm, vim, '>', cursorMax(anchor, head)); - CodeMirror.signal(cm, 'vim-mode-change', { - mode: 'visual', - subMode: vim.visualLine ? 'linewise' : - vim.visualBlock ? 'blockwise' : ''}); - } - }, - joinLines: function(cm, actionArgs, vim) { - var curStart, curEnd; - if (vim.visualMode) { - curStart = cm.getCursor('anchor'); - curEnd = cm.getCursor('head'); - if (cursorIsBefore(curEnd, curStart)) { - var tmp = curEnd; - curEnd = curStart; - curStart = tmp; - } - curEnd.ch = lineLength(cm, curEnd.line) - 1; - } else { - // Repeat is the number of lines to join. Minimum 2 lines. - var repeat = Math.max(actionArgs.repeat, 2); - curStart = cm.getCursor(); - curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1, - Infinity)); - } - var finalCh = 0; - for (var i = curStart.line; i < curEnd.line; i++) { - finalCh = lineLength(cm, curStart.line); - var tmp = Pos(curStart.line + 1, - lineLength(cm, curStart.line + 1)); - var text = cm.getRange(curStart, tmp); - text = text.replace(/\n\s*/g, ' '); - cm.replaceRange(text, curStart, tmp); - } - var curFinalPos = Pos(curStart.line, finalCh); - if (vim.visualMode) { - exitVisualMode(cm, false); - } - cm.setCursor(curFinalPos); - }, - newLineAndEnterInsertMode: function(cm, actionArgs, vim) { - vim.insertMode = true; - var insertAt = copyCursor(cm.getCursor()); - if (insertAt.line === cm.firstLine() && !actionArgs.after) { - // Special case for inserting newline before start of document. - cm.replaceRange('\n', Pos(cm.firstLine(), 0)); - cm.setCursor(cm.firstLine(), 0); - } else { - insertAt.line = (actionArgs.after) ? insertAt.line : - insertAt.line - 1; - insertAt.ch = lineLength(cm, insertAt.line); - cm.setCursor(insertAt); - var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment || - CodeMirror.commands.newlineAndIndent; - newlineFn(cm); - } - this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim); - }, - paste: function(cm, actionArgs, vim) { - var cur = copyCursor(cm.getCursor()); - var register = vimGlobalState.registerController.getRegister( - actionArgs.registerName); - var text = register.toString(); - if (!text) { - return; - } - if (actionArgs.matchIndent) { - var tabSize = cm.getOption("tabSize"); - // length that considers tabs and tabSize - var whitespaceLength = function(str) { - var tabs = (str.split("\t").length - 1); - var spaces = (str.split(" ").length - 1); - return tabs * tabSize + spaces * 1; - }; - var currentLine = cm.getLine(cm.getCursor().line); - var indent = whitespaceLength(currentLine.match(/^\s*/)[0]); - // chomp last newline b/c don't want it to match /^\s*/gm - var chompedText = text.replace(/\n$/, ''); - var wasChomped = text !== chompedText; - var firstIndent = whitespaceLength(text.match(/^\s*/)[0]); - var text = chompedText.replace(/^\s*/gm, function(wspace) { - var newIndent = indent + (whitespaceLength(wspace) - firstIndent); - if (newIndent < 0) { - return ""; - } - else if (cm.getOption("indentWithTabs")) { - var quotient = Math.floor(newIndent / tabSize); - return Array(quotient + 1).join('\t'); - } - else { - return Array(newIndent + 1).join(' '); - } - }); - text += wasChomped ? "\n" : ""; - } - if (actionArgs.repeat > 1) { - var text = Array(actionArgs.repeat + 1).join(text); - } - var linewise = register.linewise; - var blockwise = register.blockwise; - if (linewise) { - if(vim.visualMode) { - text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; - } else if (actionArgs.after) { - // Move the newline at the end to the start instead, and paste just - // before the newline character of the line we are on right now. - text = '\n' + text.slice(0, text.length - 1); - cur.ch = lineLength(cm, cur.line); - } else { - cur.ch = 0; - } - } else { - if (blockwise) { - text = text.split('\n'); - for (var i = 0; i < text.length; i++) { - text[i] = (text[i] == '') ? ' ' : text[i]; - } - } - cur.ch += actionArgs.after ? 1 : 0; - } - var curPosFinal; - var idx; - if (vim.visualMode) { - // save the pasted text for reselection if the need arises - vim.lastPastedText = text; - var lastSelectionCurEnd; - var selectedArea = getSelectedAreaRange(cm, vim); - var selectionStart = selectedArea[0]; - var selectionEnd = selectedArea[1]; - var selectedText = cm.getSelection(); - var selections = cm.listSelections(); - var emptyStrings = new Array(selections.length).join('1').split('1'); - // save the curEnd marker before it get cleared due to cm.replaceRange. - if (vim.lastSelection) { - lastSelectionCurEnd = vim.lastSelection.headMark.find(); - } - // push the previously selected text to unnamed register - vimGlobalState.registerController.unnamedRegister.setText(selectedText); - if (blockwise) { - // first delete the selected text - cm.replaceSelections(emptyStrings); - // Set new selections as per the block length of the yanked text - selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch); - cm.setCursor(selectionStart); - selectBlock(cm, selectionEnd); - cm.replaceSelections(text); - curPosFinal = selectionStart; - } else if (vim.visualBlock) { - cm.replaceSelections(emptyStrings); - cm.setCursor(selectionStart); - cm.replaceRange(text, selectionStart, selectionStart); - curPosFinal = selectionStart; - } else { - cm.replaceRange(text, selectionStart, selectionEnd); - curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); - } - // restore the the curEnd marker - if(lastSelectionCurEnd) { - vim.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd); - } - if (linewise) { - curPosFinal.ch=0; - } - } else { - if (blockwise) { - cm.setCursor(cur); - for (var i = 0; i < text.length; i++) { - var line = cur.line+i; - if (line > cm.lastLine()) { - cm.replaceRange('\n', Pos(line, 0)); - } - var lastCh = lineLength(cm, line); - if (lastCh < cur.ch) { - extendLineToColumn(cm, line, cur.ch); - } - } - cm.setCursor(cur); - selectBlock(cm, Pos(cur.line + text.length-1, cur.ch)); - cm.replaceSelections(text); - curPosFinal = cur; - } else { - cm.replaceRange(text, cur); - // Now fine tune the cursor to where we want it. - if (linewise && actionArgs.after) { - curPosFinal = Pos( - cur.line + 1, - findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); - } else if (linewise && !actionArgs.after) { - curPosFinal = Pos( - cur.line, - findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); - } else if (!linewise && actionArgs.after) { - idx = cm.indexFromPos(cur); - curPosFinal = cm.posFromIndex(idx + text.length - 1); - } else { - idx = cm.indexFromPos(cur); - curPosFinal = cm.posFromIndex(idx + text.length); - } - } - } - if (vim.visualMode) { - exitVisualMode(cm, false); - } - cm.setCursor(curPosFinal); - }, - undo: function(cm, actionArgs) { - cm.operation(function() { - repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)(); - cm.setCursor(cm.getCursor('anchor')); - }); - }, - redo: function(cm, actionArgs) { - repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)(); - }, - setRegister: function(_cm, actionArgs, vim) { - vim.inputState.registerName = actionArgs.selectedCharacter; - }, - setMark: function(cm, actionArgs, vim) { - var markName = actionArgs.selectedCharacter; - updateMark(cm, vim, markName, cm.getCursor()); - }, - replace: function(cm, actionArgs, vim) { - var replaceWith = actionArgs.selectedCharacter; - var curStart = cm.getCursor(); - var replaceTo; - var curEnd; - var selections = cm.listSelections(); - if (vim.visualMode) { - curStart = cm.getCursor('start'); - curEnd = cm.getCursor('end'); - } else { - var line = cm.getLine(curStart.line); - replaceTo = curStart.ch + actionArgs.repeat; - if (replaceTo > line.length) { - replaceTo=line.length; - } - curEnd = Pos(curStart.line, replaceTo); - } - if (replaceWith=='\n') { - if (!vim.visualMode) cm.replaceRange('', curStart, curEnd); - // special case, where vim help says to replace by just one line-break - (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm); - } else { - var replaceWithStr = cm.getRange(curStart, curEnd); - //replace all characters in range by selected, but keep linebreaks - replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith); - if (vim.visualBlock) { - // Tabs are split in visua block before replacing - var spaces = new Array(cm.getOption("tabSize")+1).join(' '); - replaceWithStr = cm.getSelection(); - replaceWithStr = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split('\n'); - cm.replaceSelections(replaceWithStr); - } else { - cm.replaceRange(replaceWithStr, curStart, curEnd); - } - if (vim.visualMode) { - curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? - selections[0].anchor : selections[0].head; - cm.setCursor(curStart); - exitVisualMode(cm, false); - } else { - cm.setCursor(offsetCursor(curEnd, 0, -1)); - } - } - }, - incrementNumberToken: function(cm, actionArgs) { - var cur = cm.getCursor(); - var lineStr = cm.getLine(cur.line); - var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi; - var match; - var start; - var end; - var numberStr; - while ((match = re.exec(lineStr)) !== null) { - start = match.index; - end = start + match[0].length; - if (cur.ch < end)break; - } - if (!actionArgs.backtrack && (end <= cur.ch))return; - if (match) { - var baseStr = match[2] || match[4] - var digits = match[3] || match[5] - var increment = actionArgs.increase ? 1 : -1; - var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()]; - var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat); - numberStr = number.toString(base); - var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : '' - if (numberStr.charAt(0) === '-') { - numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1); - } else { - numberStr = baseStr + zeroPadding + numberStr; - } - var from = Pos(cur.line, start); - var to = Pos(cur.line, end); - cm.replaceRange(numberStr, from, to); - } else { - return; - } - cm.setCursor(Pos(cur.line, start + numberStr.length - 1)); - }, - repeatLastEdit: function(cm, actionArgs, vim) { - var lastEditInputState = vim.lastEditInputState; - if (!lastEditInputState) { return; } - var repeat = actionArgs.repeat; - if (repeat && actionArgs.repeatIsExplicit) { - vim.lastEditInputState.repeatOverride = repeat; - } else { - repeat = vim.lastEditInputState.repeatOverride || repeat; - } - repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); - }, - indent: function(cm, actionArgs) { - cm.indentLine(cm.getCursor().line, actionArgs.indentRight); - }, - exitInsertMode: exitInsertMode - }; - - function defineAction(name, fn) { - actions[name] = fn; - } - - /* - * Below are miscellaneous utility functions used by vim.js - */ - - /** - * Clips cursor to ensure that line is within the buffer's range - * If includeLineBreak is true, then allow cur.ch == lineLength. - */ - function clipCursorToContent(cm, cur, includeLineBreak) { - var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); - var maxCh = lineLength(cm, line) - 1; - maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; - var ch = Math.min(Math.max(0, cur.ch), maxCh); - return Pos(line, ch); - } - function copyArgs(args) { - var ret = {}; - for (var prop in args) { - if (args.hasOwnProperty(prop)) { - ret[prop] = args[prop]; - } - } - return ret; - } - function offsetCursor(cur, offsetLine, offsetCh) { - if (typeof offsetLine === 'object') { - offsetCh = offsetLine.ch; - offsetLine = offsetLine.line; - } - return Pos(cur.line + offsetLine, cur.ch + offsetCh); - } - function getOffset(anchor, head) { - return { - line: head.line - anchor.line, - ch: head.line - anchor.line - }; - } - function commandMatches(keys, keyMap, context, inputState) { - // Partial matches are not applied. They inform the key handler - // that the current key sequence is a subsequence of a valid key - // sequence, so that the key buffer is not cleared. - var match, partial = [], full = []; - for (var i = 0; i < keyMap.length; i++) { - var command = keyMap[i]; - if (context == 'insert' && command.context != 'insert' || - command.context && command.context != context || - inputState.operator && command.type == 'action' || - !(match = commandMatch(keys, command.keys))) { continue; } - if (match == 'partial') { partial.push(command); } - if (match == 'full') { full.push(command); } - } - return { - partial: partial.length && partial, - full: full.length && full - }; - } - function commandMatch(pressed, mapped) { - if (mapped.slice(-11) == '') { - // Last character matches anything. - var prefixLen = mapped.length - 11; - var pressedPrefix = pressed.slice(0, prefixLen); - var mappedPrefix = mapped.slice(0, prefixLen); - return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' : - mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false; - } else { - return pressed == mapped ? 'full' : - mapped.indexOf(pressed) == 0 ? 'partial' : false; - } - } - function lastChar(keys) { - var match = /^.*(<[^>]+>)$/.exec(keys); - var selectedCharacter = match ? match[1] : keys.slice(-1); - if (selectedCharacter.length > 1){ - switch(selectedCharacter){ - case '': - selectedCharacter='\n'; - break; - case '': - selectedCharacter=' '; - break; - default: - selectedCharacter=''; - break; - } - } - return selectedCharacter; - } - function repeatFn(cm, fn, repeat) { - return function() { - for (var i = 0; i < repeat; i++) { - fn(cm); - } - }; - } - function copyCursor(cur) { - return Pos(cur.line, cur.ch); - } - function cursorEqual(cur1, cur2) { - return cur1.ch == cur2.ch && cur1.line == cur2.line; - } - function cursorIsBefore(cur1, cur2) { - if (cur1.line < cur2.line) { - return true; - } - if (cur1.line == cur2.line && cur1.ch < cur2.ch) { - return true; - } - return false; - } - function cursorMin(cur1, cur2) { - if (arguments.length > 2) { - cur2 = cursorMin.apply(undefined, Array.prototype.slice.call(arguments, 1)); - } - return cursorIsBefore(cur1, cur2) ? cur1 : cur2; - } - function cursorMax(cur1, cur2) { - if (arguments.length > 2) { - cur2 = cursorMax.apply(undefined, Array.prototype.slice.call(arguments, 1)); - } - return cursorIsBefore(cur1, cur2) ? cur2 : cur1; - } - function cursorIsBetween(cur1, cur2, cur3) { - // returns true if cur2 is between cur1 and cur3. - var cur1before2 = cursorIsBefore(cur1, cur2); - var cur2before3 = cursorIsBefore(cur2, cur3); - return cur1before2 && cur2before3; - } - function lineLength(cm, lineNum) { - return cm.getLine(lineNum).length; - } - function trim(s) { - if (s.trim) { - return s.trim(); - } - return s.replace(/^\s+|\s+$/g, ''); - } - function escapeRegex(s) { - return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1'); - } - function extendLineToColumn(cm, lineNum, column) { - var endCh = lineLength(cm, lineNum); - var spaces = new Array(column-endCh+1).join(' '); - cm.setCursor(Pos(lineNum, endCh)); - cm.replaceRange(spaces, cm.getCursor()); - } - // This functions selects a rectangular block - // of text with selectionEnd as any of its corner - // Height of block: - // Difference in selectionEnd.line and first/last selection.line - // Width of the block: - // Distance between selectionEnd.ch and any(first considered here) selection.ch - function selectBlock(cm, selectionEnd) { - var selections = [], ranges = cm.listSelections(); - var head = copyCursor(cm.clipPos(selectionEnd)); - var isClipped = !cursorEqual(selectionEnd, head); - var curHead = cm.getCursor('head'); - var primIndex = getIndex(ranges, curHead); - var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor); - var max = ranges.length - 1; - var index = max - primIndex > primIndex ? max : 0; - var base = ranges[index].anchor; - - var firstLine = Math.min(base.line, head.line); - var lastLine = Math.max(base.line, head.line); - var baseCh = base.ch, headCh = head.ch; - - var dir = ranges[index].head.ch - baseCh; - var newDir = headCh - baseCh; - if (dir > 0 && newDir <= 0) { - baseCh++; - if (!isClipped) { headCh--; } - } else if (dir < 0 && newDir >= 0) { - baseCh--; - if (!wasClipped) { headCh++; } - } else if (dir < 0 && newDir == -1) { - baseCh--; - headCh++; - } - for (var line = firstLine; line <= lastLine; line++) { - var range = {anchor: new Pos(line, baseCh), head: new Pos(line, headCh)}; - selections.push(range); - } - cm.setSelections(selections); - selectionEnd.ch = headCh; - base.ch = baseCh; - return base; - } - function selectForInsert(cm, head, height) { - var sel = []; - for (var i = 0; i < height; i++) { - var lineHead = offsetCursor(head, i, 0); - sel.push({anchor: lineHead, head: lineHead}); - } - cm.setSelections(sel, 0); - } - // getIndex returns the index of the cursor in the selections. - function getIndex(ranges, cursor, end) { - for (var i = 0; i < ranges.length; i++) { - var atAnchor = end != 'head' && cursorEqual(ranges[i].anchor, cursor); - var atHead = end != 'anchor' && cursorEqual(ranges[i].head, cursor); - if (atAnchor || atHead) { - return i; - } - } - return -1; - } - function getSelectedAreaRange(cm, vim) { - var lastSelection = vim.lastSelection; - var getCurrentSelectedAreaRange = function() { - var selections = cm.listSelections(); - var start = selections[0]; - var end = selections[selections.length-1]; - var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; - var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; - return [selectionStart, selectionEnd]; - }; - var getLastSelectedAreaRange = function() { - var selectionStart = cm.getCursor(); - var selectionEnd = cm.getCursor(); - var block = lastSelection.visualBlock; - if (block) { - var width = block.width; - var height = block.height; - selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width); - var selections = []; - // selectBlock creates a 'proper' rectangular block. - // We do not want that in all cases, so we manually set selections. - for (var i = selectionStart.line; i < selectionEnd.line; i++) { - var anchor = Pos(i, selectionStart.ch); - var head = Pos(i, selectionEnd.ch); - var range = {anchor: anchor, head: head}; - selections.push(range); - } - cm.setSelections(selections); - } else { - var start = lastSelection.anchorMark.find(); - var end = lastSelection.headMark.find(); - var line = end.line - start.line; - var ch = end.ch - start.ch; - selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; - if (lastSelection.visualLine) { - selectionStart = Pos(selectionStart.line, 0); - selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line)); - } - cm.setSelection(selectionStart, selectionEnd); - } - return [selectionStart, selectionEnd]; - }; - if (!vim.visualMode) { - // In case of replaying the action. - return getLastSelectedAreaRange(); - } else { - return getCurrentSelectedAreaRange(); - } - } - // Updates the previous selection with the current selection's values. This - // should only be called in visual mode. - function updateLastSelection(cm, vim) { - var anchor = vim.sel.anchor; - var head = vim.sel.head; - // To accommodate the effect of lastPastedText in the last selection - if (vim.lastPastedText) { - head = cm.posFromIndex(cm.indexFromPos(anchor) + vim.lastPastedText.length); - vim.lastPastedText = null; - } - vim.lastSelection = {'anchorMark': cm.setBookmark(anchor), - 'headMark': cm.setBookmark(head), - 'anchor': copyCursor(anchor), - 'head': copyCursor(head), - 'visualMode': vim.visualMode, - 'visualLine': vim.visualLine, - 'visualBlock': vim.visualBlock}; - } - function expandSelection(cm, start, end) { - var sel = cm.state.vim.sel; - var head = sel.head; - var anchor = sel.anchor; - var tmp; - if (cursorIsBefore(end, start)) { - tmp = end; - end = start; - start = tmp; - } - if (cursorIsBefore(head, anchor)) { - head = cursorMin(start, head); - anchor = cursorMax(anchor, end); - } else { - anchor = cursorMin(start, anchor); - head = cursorMax(head, end); - head = offsetCursor(head, 0, -1); - if (head.ch == -1 && head.line != cm.firstLine()) { - head = Pos(head.line - 1, lineLength(cm, head.line - 1)); - } - } - return [anchor, head]; - } - /** - * Updates the CodeMirror selection to match the provided vim selection. - * If no arguments are given, it uses the current vim selection state. - */ - function updateCmSelection(cm, sel, mode) { - var vim = cm.state.vim; - sel = sel || vim.sel; - var mode = mode || - vim.visualLine ? 'line' : vim.visualBlock ? 'block' : 'char'; - var cmSel = makeCmSelection(cm, sel, mode); - cm.setSelections(cmSel.ranges, cmSel.primary); - updateFakeCursor(cm); - } - function makeCmSelection(cm, sel, mode, exclusive) { - var head = copyCursor(sel.head); - var anchor = copyCursor(sel.anchor); - if (mode == 'char') { - var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; - var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0; - head = offsetCursor(sel.head, 0, headOffset); - anchor = offsetCursor(sel.anchor, 0, anchorOffset); - return { - ranges: [{anchor: anchor, head: head}], - primary: 0 - }; - } else if (mode == 'line') { - if (!cursorIsBefore(sel.head, sel.anchor)) { - anchor.ch = 0; - - var lastLine = cm.lastLine(); - if (head.line > lastLine) { - head.line = lastLine; - } - head.ch = lineLength(cm, head.line); - } else { - head.ch = 0; - anchor.ch = lineLength(cm, anchor.line); - } - return { - ranges: [{anchor: anchor, head: head}], - primary: 0 - }; - } else if (mode == 'block') { - var top = Math.min(anchor.line, head.line), - left = Math.min(anchor.ch, head.ch), - bottom = Math.max(anchor.line, head.line), - right = Math.max(anchor.ch, head.ch) + 1; - var height = bottom - top + 1; - var primary = head.line == top ? 0 : height - 1; - var ranges = []; - for (var i = 0; i < height; i++) { - ranges.push({ - anchor: Pos(top + i, left), - head: Pos(top + i, right) - }); - } - return { - ranges: ranges, - primary: primary - }; - } - } - function getHead(cm) { - var cur = cm.getCursor('head'); - if (cm.getSelection().length == 1) { - // Small corner case when only 1 character is selected. The "real" - // head is the left of head and anchor. - cur = cursorMin(cur, cm.getCursor('anchor')); - } - return cur; - } - - /** - * If moveHead is set to false, the CodeMirror selection will not be - * touched. The caller assumes the responsibility of putting the cursor - * in the right place. - */ - function exitVisualMode(cm, moveHead) { - var vim = cm.state.vim; - if (moveHead !== false) { - cm.setCursor(clipCursorToContent(cm, vim.sel.head)); - } - updateLastSelection(cm, vim); - vim.visualMode = false; - vim.visualLine = false; - vim.visualBlock = false; - CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); - if (vim.fakeCursor) { - vim.fakeCursor.clear(); - } - } - - // Remove any trailing newlines from the selection. For - // example, with the caret at the start of the last word on the line, - // 'dw' should word, but not the newline, while 'w' should advance the - // caret to the first character of the next line. - function clipToLine(cm, curStart, curEnd) { - var selection = cm.getRange(curStart, curEnd); - // Only clip if the selection ends with trailing newline + whitespace - if (/\n\s*$/.test(selection)) { - var lines = selection.split('\n'); - // We know this is all whitespace. - lines.pop(); - - // Cases: - // 1. Last word is an empty line - do not clip the trailing '\n' - // 2. Last word is not an empty line - clip the trailing '\n' - var line; - // Find the line containing the last word, and clip all whitespace up - // to it. - for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { - curEnd.line--; - curEnd.ch = 0; - } - // If the last word is not an empty line, clip an additional newline - if (line) { - curEnd.line--; - curEnd.ch = lineLength(cm, curEnd.line); - } else { - curEnd.ch = 0; - } - } - } - - // Expand the selection to line ends. - function expandSelectionToLine(_cm, curStart, curEnd) { - curStart.ch = 0; - curEnd.ch = 0; - curEnd.line++; - } - - function findFirstNonWhiteSpaceCharacter(text) { - if (!text) { - return 0; - } - var firstNonWS = text.search(/\S/); - return firstNonWS == -1 ? text.length : firstNonWS; - } - - function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) { - var cur = getHead(cm); - var line = cm.getLine(cur.line); - var idx = cur.ch; - - // Seek to first word or non-whitespace character, depending on if - // noSymbol is true. - var test = noSymbol ? wordCharTest[0] : bigWordCharTest [0]; - while (!test(line.charAt(idx))) { - idx++; - if (idx >= line.length) { return null; } - } - - if (bigWord) { - test = bigWordCharTest[0]; - } else { - test = wordCharTest[0]; - if (!test(line.charAt(idx))) { - test = wordCharTest[1]; - } - } - - var end = idx, start = idx; - while (test(line.charAt(end)) && end < line.length) { end++; } - while (test(line.charAt(start)) && start >= 0) { start--; } - start++; - - if (inclusive) { - // If present, include all whitespace after word. - // Otherwise, include all whitespace before word, except indentation. - var wordEnd = end; - while (/\s/.test(line.charAt(end)) && end < line.length) { end++; } - if (wordEnd == end) { - var wordStart = start; - while (/\s/.test(line.charAt(start - 1)) && start > 0) { start--; } - if (!start) { start = wordStart; } - } - } - return { start: Pos(cur.line, start), end: Pos(cur.line, end) }; - } - - function recordJumpPosition(cm, oldCur, newCur) { - if (!cursorEqual(oldCur, newCur)) { - vimGlobalState.jumpList.add(cm, oldCur, newCur); - } - } - - function recordLastCharacterSearch(increment, args) { - vimGlobalState.lastCharacterSearch.increment = increment; - vimGlobalState.lastCharacterSearch.forward = args.forward; - vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter; - } - - var symbolToMode = { - '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket', - '[': 'section', ']': 'section', - '*': 'comment', '/': 'comment', - 'm': 'method', 'M': 'method', - '#': 'preprocess' - }; - var findSymbolModes = { - bracket: { - isComplete: function(state) { - if (state.nextCh === state.symb) { - state.depth++; - if (state.depth >= 1)return true; - } else if (state.nextCh === state.reverseSymb) { - state.depth--; - } - return false; - } - }, - section: { - init: function(state) { - state.curMoveThrough = true; - state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}'; - }, - isComplete: function(state) { - return state.index === 0 && state.nextCh === state.symb; - } - }, - comment: { - isComplete: function(state) { - var found = state.lastCh === '*' && state.nextCh === '/'; - state.lastCh = state.nextCh; - return found; - } - }, - // TODO: The original Vim implementation only operates on level 1 and 2. - // The current implementation doesn't check for code block level and - // therefore it operates on any levels. - method: { - init: function(state) { - state.symb = (state.symb === 'm' ? '{' : '}'); - state.reverseSymb = state.symb === '{' ? '}' : '{'; - }, - isComplete: function(state) { - if (state.nextCh === state.symb)return true; - return false; - } - }, - preprocess: { - init: function(state) { - state.index = 0; - }, - isComplete: function(state) { - if (state.nextCh === '#') { - var token = state.lineText.match(/#(\w+)/)[1]; - if (token === 'endif') { - if (state.forward && state.depth === 0) { - return true; - } - state.depth++; - } else if (token === 'if') { - if (!state.forward && state.depth === 0) { - return true; - } - state.depth--; - } - if (token === 'else' && state.depth === 0)return true; - } - return false; - } - } - }; - function findSymbol(cm, repeat, forward, symb) { - var cur = copyCursor(cm.getCursor()); - var increment = forward ? 1 : -1; - var endLine = forward ? cm.lineCount() : -1; - var curCh = cur.ch; - var line = cur.line; - var lineText = cm.getLine(line); - var state = { - lineText: lineText, - nextCh: lineText.charAt(curCh), - lastCh: null, - index: curCh, - symb: symb, - reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], - forward: forward, - depth: 0, - curMoveThrough: false - }; - var mode = symbolToMode[symb]; - if (!mode)return cur; - var init = findSymbolModes[mode].init; - var isComplete = findSymbolModes[mode].isComplete; - if (init) { init(state); } - while (line !== endLine && repeat) { - state.index += increment; - state.nextCh = state.lineText.charAt(state.index); - if (!state.nextCh) { - line += increment; - state.lineText = cm.getLine(line) || ''; - if (increment > 0) { - state.index = 0; - } else { - var lineLen = state.lineText.length; - state.index = (lineLen > 0) ? (lineLen-1) : 0; - } - state.nextCh = state.lineText.charAt(state.index); - } - if (isComplete(state)) { - cur.line = line; - cur.ch = state.index; - repeat--; - } - } - if (state.nextCh || state.curMoveThrough) { - return Pos(line, state.index); - } - return cur; - } - - /* - * Returns the boundaries of the next word. If the cursor in the middle of - * the word, then returns the boundaries of the current word, starting at - * the cursor. If the cursor is at the start/end of a word, and we are going - * forward/backward, respectively, find the boundaries of the next word. - * - * @param {CodeMirror} cm CodeMirror object. - * @param {Cursor} cur The cursor position. - * @param {boolean} forward True to search forward. False to search - * backward. - * @param {boolean} bigWord True if punctuation count as part of the word. - * False if only [a-zA-Z0-9] characters count as part of the word. - * @param {boolean} emptyLineIsWord True if empty lines should be treated - * as words. - * @return {Object{from:number, to:number, line: number}} The boundaries of - * the word, or null if there are no more words. - */ - function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { - var lineNum = cur.line; - var pos = cur.ch; - var line = cm.getLine(lineNum); - var dir = forward ? 1 : -1; - var charTests = bigWord ? bigWordCharTest: wordCharTest; - - if (emptyLineIsWord && line == '') { - lineNum += dir; - line = cm.getLine(lineNum); - if (!isLine(cm, lineNum)) { - return null; - } - pos = (forward) ? 0 : line.length; - } - - while (true) { - if (emptyLineIsWord && line == '') { - return { from: 0, to: 0, line: lineNum }; - } - var stop = (dir > 0) ? line.length : -1; - var wordStart = stop, wordEnd = stop; - // Find bounds of next word. - while (pos != stop) { - var foundWord = false; - for (var i = 0; i < charTests.length && !foundWord; ++i) { - if (charTests[i](line.charAt(pos))) { - wordStart = pos; - // Advance to end of word. - while (pos != stop && charTests[i](line.charAt(pos))) { - pos += dir; - } - wordEnd = pos; - foundWord = wordStart != wordEnd; - if (wordStart == cur.ch && lineNum == cur.line && - wordEnd == wordStart + dir) { - // We started at the end of a word. Find the next one. - continue; - } else { - return { - from: Math.min(wordStart, wordEnd + 1), - to: Math.max(wordStart, wordEnd), - line: lineNum }; - } - } - } - if (!foundWord) { - pos += dir; - } - } - // Advance to next/prev line. - lineNum += dir; - if (!isLine(cm, lineNum)) { - return null; - } - line = cm.getLine(lineNum); - pos = (dir > 0) ? 0 : line.length; - } - } - - /** - * @param {CodeMirror} cm CodeMirror object. - * @param {Pos} cur The position to start from. - * @param {int} repeat Number of words to move past. - * @param {boolean} forward True to search forward. False to search - * backward. - * @param {boolean} wordEnd True to move to end of word. False to move to - * beginning of word. - * @param {boolean} bigWord True if punctuation count as part of the word. - * False if only alphabet characters count as part of the word. - * @return {Cursor} The position the cursor should move to. - */ - function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) { - var curStart = copyCursor(cur); - var words = []; - if (forward && !wordEnd || !forward && wordEnd) { - repeat++; - } - // For 'e', empty lines are not considered words, go figure. - var emptyLineIsWord = !(forward && wordEnd); - for (var i = 0; i < repeat; i++) { - var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord); - if (!word) { - var eodCh = lineLength(cm, cm.lastLine()); - words.push(forward - ? {line: cm.lastLine(), from: eodCh, to: eodCh} - : {line: 0, from: 0, to: 0}); - break; - } - words.push(word); - cur = Pos(word.line, forward ? (word.to - 1) : word.from); - } - var shortCircuit = words.length != repeat; - var firstWord = words[0]; - var lastWord = words.pop(); - if (forward && !wordEnd) { - // w - if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { - // We did not start in the middle of a word. Discard the extra word at the end. - lastWord = words.pop(); - } - return Pos(lastWord.line, lastWord.from); - } else if (forward && wordEnd) { - return Pos(lastWord.line, lastWord.to - 1); - } else if (!forward && wordEnd) { - // ge - if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { - // We did not start in the middle of a word. Discard the extra word at the end. - lastWord = words.pop(); - } - return Pos(lastWord.line, lastWord.to); - } else { - // b - return Pos(lastWord.line, lastWord.from); - } - } - - function moveToCharacter(cm, repeat, forward, character) { - var cur = cm.getCursor(); - var start = cur.ch; - var idx; - for (var i = 0; i < repeat; i ++) { - var line = cm.getLine(cur.line); - idx = charIdxInLine(start, line, character, forward, true); - if (idx == -1) { - return null; - } - start = idx; - } - return Pos(cm.getCursor().line, idx); - } - - function moveToColumn(cm, repeat) { - // repeat is always >= 1, so repeat - 1 always corresponds - // to the column we want to go to. - var line = cm.getCursor().line; - return clipCursorToContent(cm, Pos(line, repeat - 1)); - } - - function updateMark(cm, vim, markName, pos) { - if (!inArray(markName, validMarks)) { - return; - } - if (vim.marks[markName]) { - vim.marks[markName].clear(); - } - vim.marks[markName] = cm.setBookmark(pos); - } - - function charIdxInLine(start, line, character, forward, includeChar) { - // Search for char in line. - // motion_options: {forward, includeChar} - // If includeChar = true, include it too. - // If forward = true, search forward, else search backwards. - // If char is not found on this line, do nothing - var idx; - if (forward) { - idx = line.indexOf(character, start + 1); - if (idx != -1 && !includeChar) { - idx -= 1; - } - } else { - idx = line.lastIndexOf(character, start - 1); - if (idx != -1 && !includeChar) { - idx += 1; - } - } - return idx; - } - - function findParagraph(cm, head, repeat, dir, inclusive) { - var line = head.line; - var min = cm.firstLine(); - var max = cm.lastLine(); - var start, end, i = line; - function isEmpty(i) { return !cm.getLine(i); } - function isBoundary(i, dir, any) { - if (any) { return isEmpty(i) != isEmpty(i + dir); } - return !isEmpty(i) && isEmpty(i + dir); - } - if (dir) { - while (min <= i && i <= max && repeat > 0) { - if (isBoundary(i, dir)) { repeat--; } - i += dir; - } - return new Pos(i, 0); - } - - var vim = cm.state.vim; - if (vim.visualLine && isBoundary(line, 1, true)) { - var anchor = vim.sel.anchor; - if (isBoundary(anchor.line, -1, true)) { - if (!inclusive || anchor.line != line) { - line += 1; - } - } - } - var startState = isEmpty(line); - for (i = line; i <= max && repeat; i++) { - if (isBoundary(i, 1, true)) { - if (!inclusive || isEmpty(i) != startState) { - repeat--; - } - } - } - end = new Pos(i, 0); - // select boundary before paragraph for the last one - if (i > max && !startState) { startState = true; } - else { inclusive = false; } - for (i = line; i > min; i--) { - if (!inclusive || isEmpty(i) == startState || i == line) { - if (isBoundary(i, -1, true)) { break; } - } - } - start = new Pos(i, 0); - return { start: start, end: end }; - } - - function findSentence(cm, cur, repeat, dir) { - - /* - Takes an index object - { - line: the line string, - ln: line number, - pos: index in line, - dir: direction of traversal (-1 or 1) - } - and modifies the line, ln, and pos members to represent the - next valid position or sets them to null if there are - no more valid positions. - */ - function nextChar(cm, idx) { - if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) { - idx.ln += idx.dir; - if (!isLine(cm, idx.ln)) { - idx.line = null; - idx.ln = null; - idx.pos = null; - return; - } - idx.line = cm.getLine(idx.ln); - idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1; - } - else { - idx.pos += idx.dir; - } - } - - /* - Performs one iteration of traversal in forward direction - Returns an index object of the new location - */ - function forward(cm, ln, pos, dir) { - var line = cm.getLine(ln); - var stop = (line === ""); - - var curr = { - line: line, - ln: ln, - pos: pos, - dir: dir, - } - - var last_valid = { - ln: curr.ln, - pos: curr.pos, - } - - var skip_empty_lines = (curr.line === ""); - - // Move one step to skip character we start on - nextChar(cm, curr); - - while (curr.line !== null) { - last_valid.ln = curr.ln; - last_valid.pos = curr.pos; - - if (curr.line === "" && !skip_empty_lines) { - return { ln: curr.ln, pos: curr.pos, }; - } - else if (stop && curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { - return { ln: curr.ln, pos: curr.pos, }; - } - else if (isEndOfSentenceSymbol(curr.line[curr.pos]) - && !stop - && (curr.pos === curr.line.length - 1 - || isWhiteSpaceString(curr.line[curr.pos + 1]))) { - stop = true; - } - - nextChar(cm, curr); - } - - /* - Set the position to the last non whitespace character on the last - valid line in the case that we reach the end of the document. - */ - var line = cm.getLine(last_valid.ln); - last_valid.pos = 0; - for(var i = line.length - 1; i >= 0; --i) { - if (!isWhiteSpaceString(line[i])) { - last_valid.pos = i; - break; - } - } - - return last_valid; - - } - - /* - Performs one iteration of traversal in reverse direction - Returns an index object of the new location - */ - function reverse(cm, ln, pos, dir) { - var line = cm.getLine(ln); - - var curr = { - line: line, - ln: ln, - pos: pos, - dir: dir, - } - - var last_valid = { - ln: curr.ln, - pos: null, - }; - - var skip_empty_lines = (curr.line === ""); - - // Move one step to skip character we start on - nextChar(cm, curr); - - while (curr.line !== null) { - - if (curr.line === "" && !skip_empty_lines) { - if (last_valid.pos !== null) { - return last_valid; - } - else { - return { ln: curr.ln, pos: curr.pos }; - } - } - else if (isEndOfSentenceSymbol(curr.line[curr.pos]) - && last_valid.pos !== null - && !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) { - return last_valid; - } - else if (curr.line !== "" && !isWhiteSpaceString(curr.line[curr.pos])) { - skip_empty_lines = false; - last_valid = { ln: curr.ln, pos: curr.pos } - } - - nextChar(cm, curr); - } - - /* - Set the position to the first non whitespace character on the last - valid line in the case that we reach the beginning of the document. - */ - var line = cm.getLine(last_valid.ln); - last_valid.pos = 0; - for(var i = 0; i < line.length; ++i) { - if (!isWhiteSpaceString(line[i])) { - last_valid.pos = i; - break; - } - } - return last_valid; - } - - var curr_index = { - ln: cur.line, - pos: cur.ch, - }; - - while (repeat > 0) { - if (dir < 0) { - curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir); - } - else { - curr_index = forward(cm, curr_index.ln, curr_index.pos, dir); - } - repeat--; - } - - return Pos(curr_index.ln, curr_index.pos); - } - - // TODO: perhaps this finagling of start and end positions belonds - // in codemirror/replaceRange? - function selectCompanionObject(cm, head, symb, inclusive) { - var cur = head, start, end; - - var bracketRegexp = ({ - '(': /[()]/, ')': /[()]/, - '[': /[[\]]/, ']': /[[\]]/, - '{': /[{}]/, '}': /[{}]/})[symb]; - var openSym = ({ - '(': '(', ')': '(', - '[': '[', ']': '[', - '{': '{', '}': '{'})[symb]; - var curChar = cm.getLine(cur.line).charAt(cur.ch); - // Due to the behavior of scanForBracket, we need to add an offset if the - // cursor is on a matching open bracket. - var offset = curChar === openSym ? 1 : 0; - - start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp}); - end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp}); - - if (!start || !end) { - return { start: cur, end: cur }; - } - - start = start.pos; - end = end.pos; - - if ((start.line == end.line && start.ch > end.ch) - || (start.line > end.line)) { - var tmp = start; - start = end; - end = tmp; - } - - if (inclusive) { - end.ch += 1; - } else { - start.ch += 1; - } - - return { start: start, end: end }; - } - - // Takes in a symbol and a cursor and tries to simulate text objects that - // have identical opening and closing symbols - // TODO support across multiple lines - function findBeginningAndEnd(cm, head, symb, inclusive) { - var cur = copyCursor(head); - var line = cm.getLine(cur.line); - var chars = line.split(''); - var start, end, i, len; - var firstIndex = chars.indexOf(symb); - - // the decision tree is to always look backwards for the beginning first, - // but if the cursor is in front of the first instance of the symb, - // then move the cursor forward - if (cur.ch < firstIndex) { - cur.ch = firstIndex; - // Why is this line even here??? - // cm.setCursor(cur.line, firstIndex+1); - } - // otherwise if the cursor is currently on the closing symbol - else if (firstIndex < cur.ch && chars[cur.ch] == symb) { - end = cur.ch; // assign end to the current cursor - --cur.ch; // make sure to look backwards - } - - // if we're currently on the symbol, we've got a start - if (chars[cur.ch] == symb && !end) { - start = cur.ch + 1; // assign start to ahead of the cursor - } else { - // go backwards to find the start - for (i = cur.ch; i > -1 && !start; i--) { - if (chars[i] == symb) { - start = i + 1; - } - } - } - - // look forwards for the end symbol - if (start && !end) { - for (i = start, len = chars.length; i < len && !end; i++) { - if (chars[i] == symb) { - end = i; - } - } - } - - // nothing found - if (!start || !end) { - return { start: cur, end: cur }; - } - - // include the symbols - if (inclusive) { - --start; ++end; - } - - return { - start: Pos(cur.line, start), - end: Pos(cur.line, end) - }; - } - - // Search functions - defineOption('pcre', true, 'boolean'); - function SearchState() {} - SearchState.prototype = { - getQuery: function() { - return vimGlobalState.query; - }, - setQuery: function(query) { - vimGlobalState.query = query; - }, - getOverlay: function() { - return this.searchOverlay; - }, - setOverlay: function(overlay) { - this.searchOverlay = overlay; - }, - isReversed: function() { - return vimGlobalState.isReversed; - }, - setReversed: function(reversed) { - vimGlobalState.isReversed = reversed; - }, - getScrollbarAnnotate: function() { - return this.annotate; - }, - setScrollbarAnnotate: function(annotate) { - this.annotate = annotate; - } - }; - function getSearchState(cm) { - var vim = cm.state.vim; - return vim.searchState_ || (vim.searchState_ = new SearchState()); - } - function dialog(cm, template, shortText, onClose, options) { - if (cm.openDialog) { - cm.openDialog(template, onClose, { bottom: true, value: options.value, - onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp, - selectValueOnOpen: false}); - } - else { - onClose(prompt(shortText, '')); - } - } - function splitBySlash(argString) { - return splitBySeparator(argString, '/'); - } - - function findUnescapedSlashes(argString) { - return findUnescapedSeparators(argString, '/'); - } - - function splitBySeparator(argString, separator) { - var slashes = findUnescapedSeparators(argString, separator) || []; - if (!slashes.length) return []; - var tokens = []; - // in case of strings like foo/bar - if (slashes[0] !== 0) return; - for (var i = 0; i < slashes.length; i++) { - if (typeof slashes[i] == 'number') - tokens.push(argString.substring(slashes[i] + 1, slashes[i+1])); - } - return tokens; - } - - function findUnescapedSeparators(str, separator) { - if (!separator) - separator = '/'; - - var escapeNextChar = false; - var slashes = []; - for (var i = 0; i < str.length; i++) { - var c = str.charAt(i); - if (!escapeNextChar && c == separator) { - slashes.push(i); - } - escapeNextChar = !escapeNextChar && (c == '\\'); - } - return slashes; - } - - // Translates a search string from ex (vim) syntax into javascript form. - function translateRegex(str) { - // When these match, add a '\' if unescaped or remove one if escaped. - var specials = '|(){'; - // Remove, but never add, a '\' for these. - var unescape = '}'; - var escapeNextChar = false; - var out = []; - for (var i = -1; i < str.length; i++) { - var c = str.charAt(i) || ''; - var n = str.charAt(i+1) || ''; - var specialComesNext = (n && specials.indexOf(n) != -1); - if (escapeNextChar) { - if (c !== '\\' || !specialComesNext) { - out.push(c); - } - escapeNextChar = false; - } else { - if (c === '\\') { - escapeNextChar = true; - // Treat the unescape list as special for removing, but not adding '\'. - if (n && unescape.indexOf(n) != -1) { - specialComesNext = true; - } - // Not passing this test means removing a '\'. - if (!specialComesNext || n === '\\') { - out.push(c); - } - } else { - out.push(c); - if (specialComesNext && n !== '\\') { - out.push('\\'); - } - } - } - } - return out.join(''); - } - - // Translates the replace part of a search and replace from ex (vim) syntax into - // javascript form. Similar to translateRegex, but additionally fixes back references - // (translates '\[0..9]' to '$[0..9]') and follows different rules for escaping '$'. - var charUnescapes = {'\\n': '\n', '\\r': '\r', '\\t': '\t'}; - function translateRegexReplace(str) { - var escapeNextChar = false; - var out = []; - for (var i = -1; i < str.length; i++) { - var c = str.charAt(i) || ''; - var n = str.charAt(i+1) || ''; - if (charUnescapes[c + n]) { - out.push(charUnescapes[c+n]); - i++; - } else if (escapeNextChar) { - // At any point in the loop, escapeNextChar is true if the previous - // character was a '\' and was not escaped. - out.push(c); - escapeNextChar = false; - } else { - if (c === '\\') { - escapeNextChar = true; - if ((isNumber(n) || n === '$')) { - out.push('$'); - } else if (n !== '/' && n !== '\\') { - out.push('\\'); - } - } else { - if (c === '$') { - out.push('$'); - } - out.push(c); - if (n === '/') { - out.push('\\'); - } - } - } - } - return out.join(''); - } - - // Unescape \ and / in the replace part, for PCRE mode. - var unescapes = {'\\/': '/', '\\\\': '\\', '\\n': '\n', '\\r': '\r', '\\t': '\t'}; - function unescapeRegexReplace(str) { - var stream = new CodeMirror.StringStream(str); - var output = []; - while (!stream.eol()) { - // Search for \. - while (stream.peek() && stream.peek() != '\\') { - output.push(stream.next()); - } - var matched = false; - for (var matcher in unescapes) { - if (stream.match(matcher, true)) { - matched = true; - output.push(unescapes[matcher]); - break; - } - } - if (!matched) { - // Don't change anything - output.push(stream.next()); - } - } - return output.join(''); - } - - /** - * Extract the regular expression from the query and return a Regexp object. - * Returns null if the query is blank. - * If ignoreCase is passed in, the Regexp object will have the 'i' flag set. - * If smartCase is passed in, and the query contains upper case letters, - * then ignoreCase is overridden, and the 'i' flag will not be set. - * If the query contains the /i in the flag part of the regular expression, - * then both ignoreCase and smartCase are ignored, and 'i' will be passed - * through to the Regex object. - */ - function parseQuery(query, ignoreCase, smartCase) { - // First update the last search register - var lastSearchRegister = vimGlobalState.registerController.getRegister('/'); - lastSearchRegister.setText(query); - // Check if the query is already a regex. - if (query instanceof RegExp) { return query; } - // First try to extract regex + flags from the input. If no flags found, - // extract just the regex. IE does not accept flags directly defined in - // the regex string in the form /regex/flags - var slashes = findUnescapedSlashes(query); - var regexPart; - var forceIgnoreCase; - if (!slashes.length) { - // Query looks like 'regexp' - regexPart = query; - } else { - // Query looks like 'regexp/...' - regexPart = query.substring(0, slashes[0]); - var flagsPart = query.substring(slashes[0]); - forceIgnoreCase = (flagsPart.indexOf('i') != -1); - } - if (!regexPart) { - return null; - } - if (!getOption('pcre')) { - regexPart = translateRegex(regexPart); - } - if (smartCase) { - ignoreCase = (/^[^A-Z]*$/).test(regexPart); - } - var regexp = new RegExp(regexPart, - (ignoreCase || forceIgnoreCase) ? 'i' : undefined); - return regexp; - } - function showConfirm(cm, text) { - if (cm.openNotification) { - cm.openNotification('' + text + '', - {bottom: true, duration: 5000}); - } else { - alert(text); - } - } - function makePrompt(prefix, desc) { - var raw = '' + - (prefix || "") + ''; - if (desc) - raw += ' ' + desc + ''; - return raw; - } - var searchPromptDesc = '(Javascript regexp)'; - function showPrompt(cm, options) { - var shortText = (options.prefix || '') + ' ' + (options.desc || ''); - var prompt = makePrompt(options.prefix, options.desc); - dialog(cm, prompt, shortText, options.onClose, options); - } - function regexEqual(r1, r2) { - if (r1 instanceof RegExp && r2 instanceof RegExp) { - var props = ['global', 'multiline', 'ignoreCase', 'source']; - for (var i = 0; i < props.length; i++) { - var prop = props[i]; - if (r1[prop] !== r2[prop]) { - return false; - } - } - return true; - } - return false; - } - // Returns true if the query is valid. - function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { - if (!rawQuery) { - return; - } - var state = getSearchState(cm); - var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase); - if (!query) { - return; - } - highlightSearchMatches(cm, query); - if (regexEqual(query, state.getQuery())) { - return query; - } - state.setQuery(query); - return query; - } - function searchOverlay(query) { - if (query.source.charAt(0) == '^') { - var matchSol = true; - } - return { - token: function(stream) { - if (matchSol && !stream.sol()) { - stream.skipToEnd(); - return; - } - var match = stream.match(query, false); - if (match) { - if (match[0].length == 0) { - // Matched empty string, skip to next. - stream.next(); - return 'searching'; - } - if (!stream.sol()) { - // Backtrack 1 to match \b - stream.backUp(1); - if (!query.exec(stream.next() + match[0])) { - stream.next(); - return null; - } - } - stream.match(query); - return 'searching'; - } - while (!stream.eol()) { - stream.next(); - if (stream.match(query, false)) break; - } - }, - query: query - }; - } - function highlightSearchMatches(cm, query) { - var searchState = getSearchState(cm); - var overlay = searchState.getOverlay(); - if (!overlay || query != overlay.query) { - if (overlay) { - cm.removeOverlay(overlay); - } - overlay = searchOverlay(query); - cm.addOverlay(overlay); - if (cm.showMatchesOnScrollbar) { - if (searchState.getScrollbarAnnotate()) { - searchState.getScrollbarAnnotate().clear(); - } - searchState.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query)); - } - searchState.setOverlay(overlay); - } - } - function findNext(cm, prev, query, repeat) { - if (repeat === undefined) { repeat = 1; } - return cm.operation(function() { - var pos = cm.getCursor(); - var cursor = cm.getSearchCursor(query, pos); - for (var i = 0; i < repeat; i++) { - var found = cursor.find(prev); - if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); } - if (!found) { - // SearchCursor may have returned null because it hit EOF, wrap - // around and try again. - cursor = cm.getSearchCursor(query, - (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); - if (!cursor.find(prev)) { - return; - } - } - } - return cursor.from(); - }); - } - function clearSearchHighlight(cm) { - var state = getSearchState(cm); - cm.removeOverlay(getSearchState(cm).getOverlay()); - state.setOverlay(null); - if (state.getScrollbarAnnotate()) { - state.getScrollbarAnnotate().clear(); - state.setScrollbarAnnotate(null); - } - } - /** - * Check if pos is in the specified range, INCLUSIVE. - * Range can be specified with 1 or 2 arguments. - * If the first range argument is an array, treat it as an array of line - * numbers. Match pos against any of the lines. - * If the first range argument is a number, - * if there is only 1 range argument, check if pos has the same line - * number - * if there are 2 range arguments, then check if pos is in between the two - * range arguments. - */ - function isInRange(pos, start, end) { - if (typeof pos != 'number') { - // Assume it is a cursor position. Get the line number. - pos = pos.line; - } - if (start instanceof Array) { - return inArray(pos, start); - } else { - if (end) { - return (pos >= start && pos <= end); - } else { - return pos == start; - } - } - } - function getUserVisibleLines(cm) { - var scrollInfo = cm.getScrollInfo(); - var occludeToleranceTop = 6; - var occludeToleranceBottom = 10; - var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local'); - var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top; - var to = cm.coordsChar({left:0, top: bottomY}, 'local'); - return {top: from.line, bottom: to.line}; - } - - function getMarkPos(cm, vim, markName) { - if (markName == '\'') { - var history = cm.doc.history.done; - var event = history[history.length - 2]; - return event && event.ranges && event.ranges[0].head; - } else if (markName == '.') { - if (cm.doc.history.lastModTime == 0) { - return // If no changes, bail out; don't bother to copy or reverse history array. - } else { - var changeHistory = cm.doc.history.done.filter(function(el){ if (el.changes !== undefined) { return el } }); - changeHistory.reverse(); - var lastEditPos = changeHistory[0].changes[0].to; - } - return lastEditPos; - } - - var mark = vim.marks[markName]; - return mark && mark.find(); - } - - var ExCommandDispatcher = function() { - this.buildCommandMap_(); - }; - ExCommandDispatcher.prototype = { - processCommand: function(cm, input, opt_params) { - var that = this; - cm.operation(function () { - cm.curOp.isVimOp = true; - that._processCommand(cm, input, opt_params); - }); - }, - _processCommand: function(cm, input, opt_params) { - var vim = cm.state.vim; - var commandHistoryRegister = vimGlobalState.registerController.getRegister(':'); - var previousCommand = commandHistoryRegister.toString(); - if (vim.visualMode) { - exitVisualMode(cm); - } - var inputStream = new CodeMirror.StringStream(input); - // update ": with the latest command whether valid or invalid - commandHistoryRegister.setText(input); - var params = opt_params || {}; - params.input = input; - try { - this.parseInput_(cm, inputStream, params); - } catch(e) { - showConfirm(cm, e); - throw e; - } - var command; - var commandName; - if (!params.commandName) { - // If only a line range is defined, move to the line. - if (params.line !== undefined) { - commandName = 'move'; - } - } else { - command = this.matchCommand_(params.commandName); - if (command) { - commandName = command.name; - if (command.excludeFromCommandHistory) { - commandHistoryRegister.setText(previousCommand); - } - this.parseCommandArgs_(inputStream, params, command); - if (command.type == 'exToKey') { - // Handle Ex to Key mapping. - for (var i = 0; i < command.toKeys.length; i++) { - CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping'); - } - return; - } else if (command.type == 'exToEx') { - // Handle Ex to Ex mapping. - this.processCommand(cm, command.toInput); - return; - } - } - } - if (!commandName) { - showConfirm(cm, 'Not an editor command ":' + input + '"'); - return; - } - try { - exCommands[commandName](cm, params); - // Possibly asynchronous commands (e.g. substitute, which might have a - // user confirmation), are responsible for calling the callback when - // done. All others have it taken care of for them here. - if ((!command || !command.possiblyAsync) && params.callback) { - params.callback(); - } - } catch(e) { - showConfirm(cm, e); - throw e; - } - }, - parseInput_: function(cm, inputStream, result) { - inputStream.eatWhile(':'); - // Parse range. - if (inputStream.eat('%')) { - result.line = cm.firstLine(); - result.lineEnd = cm.lastLine(); - } else { - result.line = this.parseLineSpec_(cm, inputStream); - if (result.line !== undefined && inputStream.eat(',')) { - result.lineEnd = this.parseLineSpec_(cm, inputStream); - } - } - - // Parse command name. - var commandMatch = inputStream.match(/^(\w+)/); - if (commandMatch) { - result.commandName = commandMatch[1]; - } else { - result.commandName = inputStream.match(/.*/)[0]; - } - - return result; - }, - parseLineSpec_: function(cm, inputStream) { - var numberMatch = inputStream.match(/^(\d+)/); - if (numberMatch) { - // Absolute line number plus offset (N+M or N-M) is probably a typo, - // not something the user actually wanted. (NB: vim does allow this.) - return parseInt(numberMatch[1], 10) - 1; - } - switch (inputStream.next()) { - case '.': - return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); - case '$': - return this.parseLineSpecOffset_(inputStream, cm.lastLine()); - case '\'': - var markName = inputStream.next(); - var markPos = getMarkPos(cm, cm.state.vim, markName); - if (!markPos) throw new Error('Mark not set'); - return this.parseLineSpecOffset_(inputStream, markPos.line); - case '-': - case '+': - inputStream.backUp(1); - // Offset is relative to current line if not otherwise specified. - return this.parseLineSpecOffset_(inputStream, cm.getCursor().line); - default: - inputStream.backUp(1); - return undefined; - } - }, - parseLineSpecOffset_: function(inputStream, line) { - var offsetMatch = inputStream.match(/^([+-])?(\d+)/); - if (offsetMatch) { - var offset = parseInt(offsetMatch[2], 10); - if (offsetMatch[1] == "-") { - line -= offset; - } else { - line += offset; - } - } - return line; - }, - parseCommandArgs_: function(inputStream, params, command) { - if (inputStream.eol()) { - return; - } - params.argString = inputStream.match(/.*/)[0]; - // Parse command-line arguments - var delim = command.argDelimiter || /\s+/; - var args = trim(params.argString).split(delim); - if (args.length && args[0]) { - params.args = args; - } - }, - matchCommand_: function(commandName) { - // Return the command in the command map that matches the shortest - // prefix of the passed in command name. The match is guaranteed to be - // unambiguous if the defaultExCommandMap's shortNames are set up - // correctly. (see @code{defaultExCommandMap}). - for (var i = commandName.length; i > 0; i--) { - var prefix = commandName.substring(0, i); - if (this.commandMap_[prefix]) { - var command = this.commandMap_[prefix]; - if (command.name.indexOf(commandName) === 0) { - return command; - } - } - } - return null; - }, - buildCommandMap_: function() { - this.commandMap_ = {}; - for (var i = 0; i < defaultExCommandMap.length; i++) { - var command = defaultExCommandMap[i]; - var key = command.shortName || command.name; - this.commandMap_[key] = command; - } - }, - map: function(lhs, rhs, ctx) { - if (lhs != ':' && lhs.charAt(0) == ':') { - if (ctx) { throw Error('Mode not supported for ex mappings'); } - var commandName = lhs.substring(1); - if (rhs != ':' && rhs.charAt(0) == ':') { - // Ex to Ex mapping - this.commandMap_[commandName] = { - name: commandName, - type: 'exToEx', - toInput: rhs.substring(1), - user: true - }; - } else { - // Ex to key mapping - this.commandMap_[commandName] = { - name: commandName, - type: 'exToKey', - toKeys: rhs, - user: true - }; - } - } else { - if (rhs != ':' && rhs.charAt(0) == ':') { - // Key to Ex mapping. - var mapping = { - keys: lhs, - type: 'keyToEx', - exArgs: { input: rhs.substring(1) } - }; - if (ctx) { mapping.context = ctx; } - defaultKeymap.unshift(mapping); - } else { - // Key to key mapping - var mapping = { - keys: lhs, - type: 'keyToKey', - toKeys: rhs - }; - if (ctx) { mapping.context = ctx; } - defaultKeymap.unshift(mapping); - } - } - }, - unmap: function(lhs, ctx) { - if (lhs != ':' && lhs.charAt(0) == ':') { - // Ex to Ex or Ex to key mapping - if (ctx) { throw Error('Mode not supported for ex mappings'); } - var commandName = lhs.substring(1); - if (this.commandMap_[commandName] && this.commandMap_[commandName].user) { - delete this.commandMap_[commandName]; - return; - } - } else { - // Key to Ex or key to key mapping - var keys = lhs; - for (var i = 0; i < defaultKeymap.length; i++) { - if (keys == defaultKeymap[i].keys - && defaultKeymap[i].context === ctx) { - defaultKeymap.splice(i, 1); - return; - } - } - } - throw Error('No such mapping.'); - } - }; - - var exCommands = { - colorscheme: function(cm, params) { - if (!params.args || params.args.length < 1) { - showConfirm(cm, cm.getOption('theme')); - return; - } - cm.setOption('theme', params.args[0]); - }, - map: function(cm, params, ctx) { - var mapArgs = params.args; - if (!mapArgs || mapArgs.length < 2) { - if (cm) { - showConfirm(cm, 'Invalid mapping: ' + params.input); - } - return; - } - exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx); - }, - imap: function(cm, params) { this.map(cm, params, 'insert'); }, - nmap: function(cm, params) { this.map(cm, params, 'normal'); }, - vmap: function(cm, params) { this.map(cm, params, 'visual'); }, - unmap: function(cm, params, ctx) { - var mapArgs = params.args; - if (!mapArgs || mapArgs.length < 1) { - if (cm) { - showConfirm(cm, 'No such mapping: ' + params.input); - } - return; - } - exCommandDispatcher.unmap(mapArgs[0], ctx); - }, - move: function(cm, params) { - commandDispatcher.processCommand(cm, cm.state.vim, { - type: 'motion', - motion: 'moveToLineOrEdgeOfDocument', - motionArgs: { forward: false, explicitRepeat: true, - linewise: true }, - repeatOverride: params.line+1}); - }, - set: function(cm, params) { - var setArgs = params.args; - // Options passed through to the setOption/getOption calls. May be passed in by the - // local/global versions of the set command - var setCfg = params.setCfg || {}; - if (!setArgs || setArgs.length < 1) { - if (cm) { - showConfirm(cm, 'Invalid mapping: ' + params.input); - } - return; - } - var expr = setArgs[0].split('='); - var optionName = expr[0]; - var value = expr[1]; - var forceGet = false; - - if (optionName.charAt(optionName.length - 1) == '?') { - // If post-fixed with ?, then the set is actually a get. - if (value) { throw Error('Trailing characters: ' + params.argString); } - optionName = optionName.substring(0, optionName.length - 1); - forceGet = true; - } - if (value === undefined && optionName.substring(0, 2) == 'no') { - // To set boolean options to false, the option name is prefixed with - // 'no'. - optionName = optionName.substring(2); - value = false; - } - - var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean'; - if (optionIsBoolean && value == undefined) { - // Calling set with a boolean option sets it to true. - value = true; - } - // If no value is provided, then we assume this is a get. - if (!optionIsBoolean && value === undefined || forceGet) { - var oldValue = getOption(optionName, cm, setCfg); - if (oldValue instanceof Error) { - showConfirm(cm, oldValue.message); - } else if (oldValue === true || oldValue === false) { - showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName); - } else { - showConfirm(cm, ' ' + optionName + '=' + oldValue); - } - } else { - var setOptionReturn = setOption(optionName, value, cm, setCfg); - if (setOptionReturn instanceof Error) { - showConfirm(cm, setOptionReturn.message); - } - } - }, - setlocal: function (cm, params) { - // setCfg is passed through to setOption - params.setCfg = {scope: 'local'}; - this.set(cm, params); - }, - setglobal: function (cm, params) { - // setCfg is passed through to setOption - params.setCfg = {scope: 'global'}; - this.set(cm, params); - }, - registers: function(cm, params) { - var regArgs = params.args; - var registers = vimGlobalState.registerController.registers; - var regInfo = '----------Registers----------

'; - if (!regArgs) { - for (var registerName in registers) { - var text = registers[registerName].toString(); - if (text.length) { - regInfo += '"' + registerName + ' ' + text + '
'; - } - } - } else { - var registerName; - regArgs = regArgs.join(''); - for (var i = 0; i < regArgs.length; i++) { - registerName = regArgs.charAt(i); - if (!vimGlobalState.registerController.isValidRegister(registerName)) { - continue; - } - var register = registers[registerName] || new Register(); - regInfo += '"' + registerName + ' ' + register.toString() + '
'; - } - } - showConfirm(cm, regInfo); - }, - sort: function(cm, params) { - var reverse, ignoreCase, unique, number, pattern; - function parseArgs() { - if (params.argString) { - var args = new CodeMirror.StringStream(params.argString); - if (args.eat('!')) { reverse = true; } - if (args.eol()) { return; } - if (!args.eatSpace()) { return 'Invalid arguments'; } - var opts = args.match(/([dinuox]+)?\s*(\/.+\/)?\s*/); - if (!opts && !args.eol()) { return 'Invalid arguments'; } - if (opts[1]) { - ignoreCase = opts[1].indexOf('i') != -1; - unique = opts[1].indexOf('u') != -1; - var decimal = opts[1].indexOf('d') != -1 || opts[1].indexOf('n') != -1 && 1; - var hex = opts[1].indexOf('x') != -1 && 1; - var octal = opts[1].indexOf('o') != -1 && 1; - if (decimal + hex + octal > 1) { return 'Invalid arguments'; } - number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; - } - if (opts[2]) { - pattern = new RegExp(opts[2].substr(1, opts[2].length - 2), ignoreCase ? 'i' : ''); - } - } - } - var err = parseArgs(); - if (err) { - showConfirm(cm, err + ': ' + params.argString); - return; - } - var lineStart = params.line || cm.firstLine(); - var lineEnd = params.lineEnd || params.line || cm.lastLine(); - if (lineStart == lineEnd) { return; } - var curStart = Pos(lineStart, 0); - var curEnd = Pos(lineEnd, lineLength(cm, lineEnd)); - var text = cm.getRange(curStart, curEnd).split('\n'); - var numberRegex = pattern ? pattern : - (number == 'decimal') ? /(-?)([\d]+)/ : - (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i : - (number == 'octal') ? /([0-7]+)/ : null; - var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null; - var numPart = [], textPart = []; - if (number || pattern) { - for (var i = 0; i < text.length; i++) { - var matchPart = pattern ? text[i].match(pattern) : null; - if (matchPart && matchPart[0] != '') { - numPart.push(matchPart); - } else if (!pattern && numberRegex.exec(text[i])) { - numPart.push(text[i]); - } else { - textPart.push(text[i]); - } - } - } else { - textPart = text; - } - function compareFn(a, b) { - if (reverse) { var tmp; tmp = a; a = b; b = tmp; } - if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } - var anum = number && numberRegex.exec(a); - var bnum = number && numberRegex.exec(b); - if (!anum) { return a < b ? -1 : 1; } - anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix); - bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix); - return anum - bnum; - } - function comparePatternFn(a, b) { - if (reverse) { var tmp; tmp = a; a = b; b = tmp; } - if (ignoreCase) { a[0] = a[0].toLowerCase(); b[0] = b[0].toLowerCase(); } - return (a[0] < b[0]) ? -1 : 1; - } - numPart.sort(pattern ? comparePatternFn : compareFn); - if (pattern) { - for (var i = 0; i < numPart.length; i++) { - numPart[i] = numPart[i].input; - } - } else if (!number) { textPart.sort(compareFn); } - text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart); - if (unique) { // Remove duplicate lines - var textOld = text; - var lastLine; - text = []; - for (var i = 0; i < textOld.length; i++) { - if (textOld[i] != lastLine) { - text.push(textOld[i]); - } - lastLine = textOld[i]; - } - } - cm.replaceRange(text.join('\n'), curStart, curEnd); - }, - global: function(cm, params) { - // a global command is of the form - // :[range]g/pattern/[cmd] - // argString holds the string /pattern/[cmd] - var argString = params.argString; - if (!argString) { - showConfirm(cm, 'Regular Expression missing from global'); - return; - } - // range is specified here - var lineStart = (params.line !== undefined) ? params.line : cm.firstLine(); - var lineEnd = params.lineEnd || params.line || cm.lastLine(); - // get the tokens from argString - var tokens = splitBySlash(argString); - var regexPart = argString, cmd; - if (tokens.length) { - regexPart = tokens[0]; - cmd = tokens.slice(1, tokens.length).join('/'); - } - if (regexPart) { - // If regex part is empty, then use the previous query. Otherwise - // use the regex part as the new query. - try { - updateSearchQuery(cm, regexPart, true /** ignoreCase */, - true /** smartCase */); - } catch (e) { - showConfirm(cm, 'Invalid regex: ' + regexPart); - return; - } - } - // now that we have the regexPart, search for regex matches in the - // specified range of lines - var query = getSearchState(cm).getQuery(); - var matchedLines = [], content = ''; - for (var i = lineStart; i <= lineEnd; i++) { - var matched = query.test(cm.getLine(i)); - if (matched) { - matchedLines.push(i+1); - content+= cm.getLine(i) + '
'; - } - } - // if there is no [cmd], just display the list of matched lines - if (!cmd) { - showConfirm(cm, content); - return; - } - var index = 0; - var nextCommand = function() { - if (index < matchedLines.length) { - var command = matchedLines[index] + cmd; - exCommandDispatcher.processCommand(cm, command, { - callback: nextCommand - }); - } - index++; - }; - nextCommand(); - }, - substitute: function(cm, params) { - if (!cm.getSearchCursor) { - throw new Error('Search feature not available. Requires searchcursor.js or ' + - 'any other getSearchCursor implementation.'); - } - var argString = params.argString; - var tokens = argString ? splitBySeparator(argString, argString[0]) : []; - var regexPart, replacePart = '', trailing, flagsPart, count; - var confirm = false; // Whether to confirm each replace. - var global = false; // True to replace all instances on a line, false to replace only 1. - if (tokens.length) { - regexPart = tokens[0]; - replacePart = tokens[1]; - if (regexPart && regexPart[regexPart.length - 1] === '$') { - regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n'; - replacePart = replacePart ? replacePart + '\n' : '\n'; - } - if (replacePart !== undefined) { - if (getOption('pcre')) { - replacePart = unescapeRegexReplace(replacePart); - } else { - replacePart = translateRegexReplace(replacePart); - } - vimGlobalState.lastSubstituteReplacePart = replacePart; - } - trailing = tokens[2] ? tokens[2].split(' ') : []; - } else { - // either the argString is empty or its of the form ' hello/world' - // actually splitBySlash returns a list of tokens - // only if the string starts with a '/' - if (argString && argString.length) { - showConfirm(cm, 'Substitutions should be of the form ' + - ':s/pattern/replace/'); - return; - } - } - // After the 3rd slash, we can have flags followed by a space followed - // by count. - if (trailing) { - flagsPart = trailing[0]; - count = parseInt(trailing[1]); - if (flagsPart) { - if (flagsPart.indexOf('c') != -1) { - confirm = true; - flagsPart.replace('c', ''); - } - if (flagsPart.indexOf('g') != -1) { - global = true; - flagsPart.replace('g', ''); - } - regexPart = regexPart.replace(/\//g, "\\/") + '/' + flagsPart; - } - } - if (regexPart) { - // If regex part is empty, then use the previous query. Otherwise use - // the regex part as the new query. - try { - updateSearchQuery(cm, regexPart, true /** ignoreCase */, - true /** smartCase */); - } catch (e) { - showConfirm(cm, 'Invalid regex: ' + regexPart); - return; - } - } - replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart; - if (replacePart === undefined) { - showConfirm(cm, 'No previous substitute regular expression'); - return; - } - var state = getSearchState(cm); - var query = state.getQuery(); - var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; - var lineEnd = params.lineEnd || lineStart; - if (lineStart == cm.firstLine() && lineEnd == cm.lastLine()) { - lineEnd = Infinity; - } - if (count) { - lineStart = lineEnd; - lineEnd = lineStart + count - 1; - } - var startPos = clipCursorToContent(cm, Pos(lineStart, 0)); - var cursor = cm.getSearchCursor(query, startPos); - doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback); - }, - redo: CodeMirror.commands.redo, - undo: CodeMirror.commands.undo, - write: function(cm) { - if (CodeMirror.commands.save) { - // If a save command is defined, call it. - CodeMirror.commands.save(cm); - } else if (cm.save) { - // Saves to text area if no save command is defined and cm.save() is available. - cm.save(); - } - }, - nohlsearch: function(cm) { - clearSearchHighlight(cm); - }, - yank: function (cm) { - var cur = copyCursor(cm.getCursor()); - var line = cur.line; - var lineText = cm.getLine(line); - vimGlobalState.registerController.pushText( - '0', 'yank', lineText, true, true); - }, - delmarks: function(cm, params) { - if (!params.argString || !trim(params.argString)) { - showConfirm(cm, 'Argument required'); - return; - } - - var state = cm.state.vim; - var stream = new CodeMirror.StringStream(trim(params.argString)); - while (!stream.eol()) { - stream.eatSpace(); - - // Record the streams position at the beginning of the loop for use - // in error messages. - var count = stream.pos; - - if (!stream.match(/[a-zA-Z]/, false)) { - showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); - return; - } - - var sym = stream.next(); - // Check if this symbol is part of a range - if (stream.match('-', true)) { - // This symbol is part of a range. - - // The range must terminate at an alphabetic character. - if (!stream.match(/[a-zA-Z]/, false)) { - showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); - return; - } - - var startMark = sym; - var finishMark = stream.next(); - // The range must terminate at an alphabetic character which - // shares the same case as the start of the range. - if (isLowerCase(startMark) && isLowerCase(finishMark) || - isUpperCase(startMark) && isUpperCase(finishMark)) { - var start = startMark.charCodeAt(0); - var finish = finishMark.charCodeAt(0); - if (start >= finish) { - showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); - return; - } - - // Because marks are always ASCII values, and we have - // determined that they are the same case, we can use - // their char codes to iterate through the defined range. - for (var j = 0; j <= finish - start; j++) { - var mark = String.fromCharCode(start + j); - delete state.marks[mark]; - } - } else { - showConfirm(cm, 'Invalid argument: ' + startMark + '-'); - return; - } - } else { - // This symbol is a valid mark, and is not part of a range. - delete state.marks[sym]; - } - } - } - }; - - var exCommandDispatcher = new ExCommandDispatcher(); - - /** - * @param {CodeMirror} cm CodeMirror instance we are in. - * @param {boolean} confirm Whether to confirm each replace. - * @param {Cursor} lineStart Line to start replacing from. - * @param {Cursor} lineEnd Line to stop replacing at. - * @param {RegExp} query Query for performing matches with. - * @param {string} replaceWith Text to replace matches with. May contain $1, - * $2, etc for replacing captured groups using Javascript replace. - * @param {function()} callback A callback for when the replace is done. - */ - function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, - replaceWith, callback) { - // Set up all the functions. - cm.state.vim.exMode = true; - var done = false; - var lastPos = searchCursor.from(); - function replaceAll() { - cm.operation(function() { - while (!done) { - replace(); - next(); - } - stop(); - }); - } - function replace() { - var text = cm.getRange(searchCursor.from(), searchCursor.to()); - var newText = text.replace(query, replaceWith); - searchCursor.replace(newText); - } - function next() { - // The below only loops to skip over multiple occurrences on the same - // line when 'global' is not true. - while(searchCursor.findNext() && - isInRange(searchCursor.from(), lineStart, lineEnd)) { - if (!global && lastPos && searchCursor.from().line == lastPos.line) { - continue; - } - cm.scrollIntoView(searchCursor.from(), 30); - cm.setSelection(searchCursor.from(), searchCursor.to()); - lastPos = searchCursor.from(); - done = false; - return; - } - done = true; - } - function stop(close) { - if (close) { close(); } - cm.focus(); - if (lastPos) { - cm.setCursor(lastPos); - var vim = cm.state.vim; - vim.exMode = false; - vim.lastHPos = vim.lastHSPos = lastPos.ch; - } - if (callback) { callback(); } - } - function onPromptKeyDown(e, _value, close) { - // Swallow all keys. - CodeMirror.e_stop(e); - var keyName = CodeMirror.keyName(e); - switch (keyName) { - case 'Y': - replace(); next(); break; - case 'N': - next(); break; - case 'A': - // replaceAll contains a call to close of its own. We don't want it - // to fire too early or multiple times. - var savedCallback = callback; - callback = undefined; - cm.operation(replaceAll); - callback = savedCallback; - break; - case 'L': - replace(); - // fall through and exit. - case 'Q': - case 'Esc': - case 'Ctrl-C': - case 'Ctrl-[': - stop(close); - break; - } - if (done) { stop(close); } - return true; - } - - // Actually do replace. - next(); - if (done) { - showConfirm(cm, 'No matches for ' + query.source); - return; - } - if (!confirm) { - replaceAll(); - if (callback) { callback(); } - return; - } - showPrompt(cm, { - prefix: 'replace with ' + replaceWith + ' (y/n/a/q/l)', - onKeyDown: onPromptKeyDown - }); - } - - CodeMirror.keyMap.vim = { - attach: attachVimMap, - detach: detachVimMap, - call: cmKey - }; - - function exitInsertMode(cm) { - var vim = cm.state.vim; - var macroModeState = vimGlobalState.macroModeState; - var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.'); - var isPlaying = macroModeState.isPlaying; - var lastChange = macroModeState.lastInsertModeChanges; - // In case of visual block, the insertModeChanges are not saved as a - // single word, so we convert them to a single word - // so as to update the ". register as expected in real vim. - var text = []; - if (!isPlaying) { - var selLength = lastChange.inVisualBlock && vim.lastSelection ? - vim.lastSelection.visualBlock.height : 1; - var changes = lastChange.changes; - var text = []; - var i = 0; - // In case of multiple selections in blockwise visual, - // the inserted text, for example: 'foo', is stored as - // 'f', 'f', InsertModeKey 'o', 'o', 'o', 'o'. (if you have a block with 2 lines). - // We push the contents of the changes array as per the following: - // 1. In case of InsertModeKey, just increment by 1. - // 2. In case of a character, jump by selLength (2 in the example). - while (i < changes.length) { - // This loop will convert 'ffoooo' to 'foo'. - text.push(changes[i]); - if (changes[i] instanceof InsertModeKey) { - i++; - } else { - i+= selLength; - } - } - lastChange.changes = text; - cm.off('change', onChange); - CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown); - } - if (!isPlaying && vim.insertModeRepeat > 1) { - // Perform insert mode repeat for commands like 3,a and 3,o. - repeatLastEdit(cm, vim, vim.insertModeRepeat - 1, - true /** repeatForInsert */); - vim.lastEditInputState.repeatOverride = vim.insertModeRepeat; - } - delete vim.insertModeRepeat; - vim.insertMode = false; - cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1); - cm.setOption('keyMap', 'vim'); - cm.setOption('disableInput', true); - cm.toggleOverwrite(false); // exit replace mode if we were in it. - // update the ". register before exiting insert mode - insertModeChangeRegister.setText(lastChange.changes.join('')); - CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"}); - if (macroModeState.isRecording) { - logInsertModeChange(macroModeState); - } - } - - function _mapCommand(command) { - defaultKeymap.unshift(command); - } - - function mapCommand(keys, type, name, args, extra) { - var command = {keys: keys, type: type}; - command[type] = name; - command[type + "Args"] = args; - for (var key in extra) - command[key] = extra[key]; - _mapCommand(command); - } - - // The timeout in milliseconds for the two-character ESC keymap should be - // adjusted according to your typing speed to prevent false positives. - defineOption('insertModeEscKeysTimeout', 200, 'number'); - - CodeMirror.keyMap['vim-insert'] = { - // TODO: override navigation keys so that Esc will cancel automatic - // indentation from o, O, i_ - fallthrough: ['default'], - attach: attachVimMap, - detach: detachVimMap, - call: cmKey - }; - - CodeMirror.keyMap['vim-replace'] = { - 'Backspace': 'goCharLeft', - fallthrough: ['vim-insert'], - attach: attachVimMap, - detach: detachVimMap, - call: cmKey - }; - - function executeMacroRegister(cm, vim, macroModeState, registerName) { - var register = vimGlobalState.registerController.getRegister(registerName); - if (registerName == ':') { - // Read-only register containing last Ex command. - if (register.keyBuffer[0]) { - exCommandDispatcher.processCommand(cm, register.keyBuffer[0]); - } - macroModeState.isPlaying = false; - return; - } - var keyBuffer = register.keyBuffer; - var imc = 0; - macroModeState.isPlaying = true; - macroModeState.replaySearchQueries = register.searchQueries.slice(0); - for (var i = 0; i < keyBuffer.length; i++) { - var text = keyBuffer[i]; - var match, key; - while (text) { - // Pull off one command key, which is either a single character - // or a special sequence wrapped in '<' and '>', e.g. ''. - match = (/<\w+-.+?>|<\w+>|./).exec(text); - key = match[0]; - text = text.substring(match.index + key.length); - CodeMirror.Vim.handleKey(cm, key, 'macro'); - if (vim.insertMode) { - var changes = register.insertModeChanges[imc++].changes; - vimGlobalState.macroModeState.lastInsertModeChanges.changes = - changes; - repeatInsertModeChanges(cm, changes, 1); - exitInsertMode(cm); - } - } - } - macroModeState.isPlaying = false; - } - - function logKey(macroModeState, key) { - if (macroModeState.isPlaying) { return; } - var registerName = macroModeState.latestRegister; - var register = vimGlobalState.registerController.getRegister(registerName); - if (register) { - register.pushText(key); - } - } - - function logInsertModeChange(macroModeState) { - if (macroModeState.isPlaying) { return; } - var registerName = macroModeState.latestRegister; - var register = vimGlobalState.registerController.getRegister(registerName); - if (register && register.pushInsertModeChanges) { - register.pushInsertModeChanges(macroModeState.lastInsertModeChanges); - } - } - - function logSearchQuery(macroModeState, query) { - if (macroModeState.isPlaying) { return; } - var registerName = macroModeState.latestRegister; - var register = vimGlobalState.registerController.getRegister(registerName); - if (register && register.pushSearchQuery) { - register.pushSearchQuery(query); - } - } - - /** - * Listens for changes made in insert mode. - * Should only be active in insert mode. - */ - function onChange(cm, changeObj) { - var macroModeState = vimGlobalState.macroModeState; - var lastChange = macroModeState.lastInsertModeChanges; - if (!macroModeState.isPlaying) { - while(changeObj) { - lastChange.expectCursorActivityForChange = true; - if (changeObj.origin == '+input' || changeObj.origin == 'paste' - || changeObj.origin === undefined /* only in testing */) { - var text = changeObj.text.join('\n'); - if (lastChange.maybeReset) { - lastChange.changes = []; - lastChange.maybeReset = false; - } - if (cm.state.overwrite && !/\n/.test(text)) { - lastChange.changes.push([text]); - } else { - lastChange.changes.push(text); - } - } - // Change objects may be chained with next. - changeObj = changeObj.next; - } - } - } - - /** - * Listens for any kind of cursor activity on CodeMirror. - */ - function onCursorActivity(cm) { - var vim = cm.state.vim; - if (vim.insertMode) { - // Tracking cursor activity in insert mode (for macro support). - var macroModeState = vimGlobalState.macroModeState; - if (macroModeState.isPlaying) { return; } - var lastChange = macroModeState.lastInsertModeChanges; - if (lastChange.expectCursorActivityForChange) { - lastChange.expectCursorActivityForChange = false; - } else { - // Cursor moved outside the context of an edit. Reset the change. - lastChange.maybeReset = true; - } - } else if (!cm.curOp.isVimOp) { - handleExternalSelection(cm, vim); - } - if (vim.visualMode) { - updateFakeCursor(cm); - } - } - function updateFakeCursor(cm) { - var vim = cm.state.vim; - var from = clipCursorToContent(cm, copyCursor(vim.sel.head)); - var to = offsetCursor(from, 0, 1); - if (vim.fakeCursor) { - vim.fakeCursor.clear(); - } - vim.fakeCursor = cm.markText(from, to, {className: 'cm-animate-fat-cursor'}); - } - function handleExternalSelection(cm, vim) { - var anchor = cm.getCursor('anchor'); - var head = cm.getCursor('head'); - // Enter or exit visual mode to match mouse selection. - if (vim.visualMode && !cm.somethingSelected()) { - exitVisualMode(cm, false); - } else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) { - vim.visualMode = true; - vim.visualLine = false; - CodeMirror.signal(cm, "vim-mode-change", {mode: "visual"}); - } - if (vim.visualMode) { - // Bind CodeMirror selection model to vim selection model. - // Mouse selections are considered visual characterwise. - var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0; - var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0; - head = offsetCursor(head, 0, headOffset); - anchor = offsetCursor(anchor, 0, anchorOffset); - vim.sel = { - anchor: anchor, - head: head - }; - updateMark(cm, vim, '<', cursorMin(head, anchor)); - updateMark(cm, vim, '>', cursorMax(head, anchor)); - } else if (!vim.insertMode) { - // Reset lastHPos if selection was modified by something outside of vim mode e.g. by mouse. - vim.lastHPos = cm.getCursor().ch; - } - } - - /** Wrapper for special keys pressed in insert mode */ - function InsertModeKey(keyName) { - this.keyName = keyName; - } - - /** - * Handles raw key down events from the text area. - * - Should only be active in insert mode. - * - For recording deletes in insert mode. - */ - function onKeyEventTargetKeyDown(e) { - var macroModeState = vimGlobalState.macroModeState; - var lastChange = macroModeState.lastInsertModeChanges; - var keyName = CodeMirror.keyName(e); - if (!keyName) { return; } - function onKeyFound() { - if (lastChange.maybeReset) { - lastChange.changes = []; - lastChange.maybeReset = false; - } - lastChange.changes.push(new InsertModeKey(keyName)); - return true; - } - if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { - CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound); - } - } - - /** - * Repeats the last edit, which includes exactly 1 command and at most 1 - * insert. Operator and motion commands are read from lastEditInputState, - * while action commands are read from lastEditActionCommand. - * - * If repeatForInsert is true, then the function was called by - * exitInsertMode to repeat the insert mode changes the user just made. The - * corresponding enterInsertMode call was made with a count. - */ - function repeatLastEdit(cm, vim, repeat, repeatForInsert) { - var macroModeState = vimGlobalState.macroModeState; - macroModeState.isPlaying = true; - var isAction = !!vim.lastEditActionCommand; - var cachedInputState = vim.inputState; - function repeatCommand() { - if (isAction) { - commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand); - } else { - commandDispatcher.evalInput(cm, vim); - } - } - function repeatInsert(repeat) { - if (macroModeState.lastInsertModeChanges.changes.length > 0) { - // For some reason, repeat cw in desktop VIM does not repeat - // insert mode changes. Will conform to that behavior. - repeat = !vim.lastEditActionCommand ? 1 : repeat; - var changeObject = macroModeState.lastInsertModeChanges; - repeatInsertModeChanges(cm, changeObject.changes, repeat); - } - } - vim.inputState = vim.lastEditInputState; - if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) { - // o and O repeat have to be interlaced with insert repeats so that the - // insertions appear on separate lines instead of the last line. - for (var i = 0; i < repeat; i++) { - repeatCommand(); - repeatInsert(1); - } - } else { - if (!repeatForInsert) { - // Hack to get the cursor to end up at the right place. If I is - // repeated in insert mode repeat, cursor will be 1 insert - // change set left of where it should be. - repeatCommand(); - } - repeatInsert(repeat); - } - vim.inputState = cachedInputState; - if (vim.insertMode && !repeatForInsert) { - // Don't exit insert mode twice. If repeatForInsert is set, then we - // were called by an exitInsertMode call lower on the stack. - exitInsertMode(cm); - } - macroModeState.isPlaying = false; - } - - function repeatInsertModeChanges(cm, changes, repeat) { - function keyHandler(binding) { - if (typeof binding == 'string') { - CodeMirror.commands[binding](cm); - } else { - binding(cm); - } - return true; - } - var head = cm.getCursor('head'); - var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock; - if (inVisualBlock) { - // Set up block selection again for repeating the changes. - var vim = cm.state.vim; - var lastSel = vim.lastSelection; - var offset = getOffset(lastSel.anchor, lastSel.head); - selectForInsert(cm, head, offset.line + 1); - repeat = cm.listSelections().length; - cm.setCursor(head); - } - for (var i = 0; i < repeat; i++) { - if (inVisualBlock) { - cm.setCursor(offsetCursor(head, i, 0)); - } - for (var j = 0; j < changes.length; j++) { - var change = changes[j]; - if (change instanceof InsertModeKey) { - CodeMirror.lookupKey(change.keyName, 'vim-insert', keyHandler); - } else if (typeof change == "string") { - var cur = cm.getCursor(); - cm.replaceRange(change, cur, cur); - } else { - var start = cm.getCursor(); - var end = offsetCursor(start, 0, change[0].length); - cm.replaceRange(change[0], start, end); - } - } - } - if (inVisualBlock) { - cm.setCursor(offsetCursor(head, 0, 1)); - } - } - - resetVimGlobalState(); - return vimApi; - }; - // Initialize Vim and make it available as an API. - CodeMirror.Vim = Vim(); - }); - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - // A rough approximation of Sublime Text's keybindings - // Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(3), __webpack_require__(5)); - else if (typeof define == "function" && define.amd) // AMD - define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var cmds = CodeMirror.commands; - var Pos = CodeMirror.Pos; - - // This is not exactly Sublime's algorithm. I couldn't make heads or tails of that. - function findPosSubword(doc, start, dir) { - if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1)); - var line = doc.getLine(start.line); - if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0)); - var state = "start", type; - for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) { - var next = line.charAt(dir < 0 ? pos - 1 : pos); - var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o"; - if (cat == "w" && next.toUpperCase() == next) cat = "W"; - if (state == "start") { - if (cat != "o") { state = "in"; type = cat; } - } else if (state == "in") { - if (type != cat) { - if (type == "w" && cat == "W" && dir < 0) pos--; - if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; } - break; - } - } - } - return Pos(start.line, pos); - } - - function moveSubword(cm, dir) { - cm.extendSelectionsBy(function(range) { - if (cm.display.shift || cm.doc.extend || range.empty()) - return findPosSubword(cm.doc, range.head, dir); - else - return dir < 0 ? range.from() : range.to(); - }); - } - - cmds.goSubwordLeft = function(cm) { moveSubword(cm, -1); }; - cmds.goSubwordRight = function(cm) { moveSubword(cm, 1); }; - - cmds.scrollLineUp = function(cm) { - var info = cm.getScrollInfo(); - if (!cm.somethingSelected()) { - var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local"); - if (cm.getCursor().line >= visibleBottomLine) - cm.execCommand("goLineUp"); - } - cm.scrollTo(null, info.top - cm.defaultTextHeight()); - }; - cmds.scrollLineDown = function(cm) { - var info = cm.getScrollInfo(); - if (!cm.somethingSelected()) { - var visibleTopLine = cm.lineAtHeight(info.top, "local")+1; - if (cm.getCursor().line <= visibleTopLine) - cm.execCommand("goLineDown"); - } - cm.scrollTo(null, info.top + cm.defaultTextHeight()); - }; - - cmds.splitSelectionByLine = function(cm) { - var ranges = cm.listSelections(), lineRanges = []; - for (var i = 0; i < ranges.length; i++) { - var from = ranges[i].from(), to = ranges[i].to(); - for (var line = from.line; line <= to.line; ++line) - if (!(to.line > from.line && line == to.line && to.ch == 0)) - lineRanges.push({anchor: line == from.line ? from : Pos(line, 0), - head: line == to.line ? to : Pos(line)}); - } - cm.setSelections(lineRanges, 0); - }; - - cmds.singleSelectionTop = function(cm) { - var range = cm.listSelections()[0]; - cm.setSelection(range.anchor, range.head, {scroll: false}); - }; - - cmds.selectLine = function(cm) { - var ranges = cm.listSelections(), extended = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - extended.push({anchor: Pos(range.from().line, 0), - head: Pos(range.to().line + 1, 0)}); - } - cm.setSelections(extended); - }; - - function insertLine(cm, above) { - if (cm.isReadOnly()) return CodeMirror.Pass - cm.operation(function() { - var len = cm.listSelections().length, newSelection = [], last = -1; - for (var i = 0; i < len; i++) { - var head = cm.listSelections()[i].head; - if (head.line <= last) continue; - var at = Pos(head.line + (above ? 0 : 1), 0); - cm.replaceRange("\n", at, null, "+insertLine"); - cm.indentLine(at.line, null, true); - newSelection.push({head: at, anchor: at}); - last = head.line + 1; - } - cm.setSelections(newSelection); - }); - cm.execCommand("indentAuto"); - } - - cmds.insertLineAfter = function(cm) { return insertLine(cm, false); }; - - cmds.insertLineBefore = function(cm) { return insertLine(cm, true); }; - - function wordAt(cm, pos) { - var start = pos.ch, end = start, line = cm.getLine(pos.line); - while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start; - while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end; - return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)}; - } - - cmds.selectNextOccurrence = function(cm) { - var from = cm.getCursor("from"), to = cm.getCursor("to"); - var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel; - if (CodeMirror.cmpPos(from, to) == 0) { - var word = wordAt(cm, from); - if (!word.word) return; - cm.setSelection(word.from, word.to); - fullWord = true; - } else { - var text = cm.getRange(from, to); - var query = fullWord ? new RegExp("\\b" + text + "\\b") : text; - var cur = cm.getSearchCursor(query, to); - var found = cur.findNext(); - if (!found) { - cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0)); - found = cur.findNext(); - } - if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) - return CodeMirror.Pass - cm.addSelection(cur.from(), cur.to()); - } - if (fullWord) - cm.state.sublimeFindFullWord = cm.doc.sel; - }; - - function addCursorToSelection(cm, dir) { - var ranges = cm.listSelections(), newRanges = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - var newAnchor = cm.findPosV( - range.anchor, dir, "line", range.anchor.goalColumn); - var newHead = cm.findPosV( - range.head, dir, "line", range.head.goalColumn); - newAnchor.goalColumn = range.anchor.goalColumn != null ? - range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left; - newHead.goalColumn = range.head.goalColumn != null ? - range.head.goalColumn : cm.cursorCoords(range.head, "div").left; - var newRange = {anchor: newAnchor, head: newHead}; - newRanges.push(range); - newRanges.push(newRange); - } - cm.setSelections(newRanges); - } - cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); }; - cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); }; - - function isSelectedRange(ranges, from, to) { - for (var i = 0; i < ranges.length; i++) - if (ranges[i].from() == from && ranges[i].to() == to) return true - return false - } - - var mirror = "(){}[]"; - function selectBetweenBrackets(cm) { - var ranges = cm.listSelections(), newRanges = [] - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1); - if (!opening) return false; - for (;;) { - var closing = cm.scanForBracket(pos, 1); - if (!closing) return false; - if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { - var startPos = Pos(opening.pos.line, opening.pos.ch + 1); - if (CodeMirror.cmpPos(startPos, range.from()) == 0 && - CodeMirror.cmpPos(closing.pos, range.to()) == 0) { - opening = cm.scanForBracket(opening.pos, -1); - if (!opening) return false; - } else { - newRanges.push({anchor: startPos, head: closing.pos}); - break; - } - } - pos = Pos(closing.pos.line, closing.pos.ch + 1); - } - } - cm.setSelections(newRanges); - return true; - } - - cmds.selectScope = function(cm) { - selectBetweenBrackets(cm) || cm.execCommand("selectAll"); - }; - cmds.selectBetweenBrackets = function(cm) { - if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; - }; - - cmds.goToBracket = function(cm) { - cm.extendSelectionsBy(function(range) { - var next = cm.scanForBracket(range.head, 1); - if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; - var prev = cm.scanForBracket(range.head, -1); - return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head; - }); - }; - - cmds.swapLineUp = function(cm) { - if (cm.isReadOnly()) return CodeMirror.Pass - var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i], from = range.from().line - 1, to = range.to().line; - newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch), - head: Pos(range.head.line - 1, range.head.ch)}); - if (range.to().ch == 0 && !range.empty()) --to; - if (from > at) linesToMove.push(from, to); - else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; - at = to; - } - cm.operation(function() { - for (var i = 0; i < linesToMove.length; i += 2) { - var from = linesToMove[i], to = linesToMove[i + 1]; - var line = cm.getLine(from); - cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); - if (to > cm.lastLine()) - cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine"); - else - cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); - } - cm.setSelections(newSels); - cm.scrollIntoView(); - }); - }; - - cmds.swapLineDown = function(cm) { - if (cm.isReadOnly()) return CodeMirror.Pass - var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; - for (var i = ranges.length - 1; i >= 0; i--) { - var range = ranges[i], from = range.to().line + 1, to = range.from().line; - if (range.to().ch == 0 && !range.empty()) from--; - if (from < at) linesToMove.push(from, to); - else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; - at = to; - } - cm.operation(function() { - for (var i = linesToMove.length - 2; i >= 0; i -= 2) { - var from = linesToMove[i], to = linesToMove[i + 1]; - var line = cm.getLine(from); - if (from == cm.lastLine()) - cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine"); - else - cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); - cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); - } - cm.scrollIntoView(); - }); - }; - - cmds.toggleCommentIndented = function(cm) { - cm.toggleComment({ indent: true }); - } - - cmds.joinLines = function(cm) { - var ranges = cm.listSelections(), joined = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i], from = range.from(); - var start = from.line, end = range.to().line; - while (i < ranges.length - 1 && ranges[i + 1].from().line == end) - end = ranges[++i].to().line; - joined.push({start: start, end: end, anchor: !range.empty() && from}); - } - cm.operation(function() { - var offset = 0, ranges = []; - for (var i = 0; i < joined.length; i++) { - var obj = joined[i]; - var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head; - for (var line = obj.start; line <= obj.end; line++) { - var actual = line - offset; - if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1); - if (actual < cm.lastLine()) { - cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length)); - ++offset; - } - } - ranges.push({anchor: anchor || head, head: head}); - } - cm.setSelections(ranges, 0); - }); - }; - - cmds.duplicateLine = function(cm) { - cm.operation(function() { - var rangeCount = cm.listSelections().length; - for (var i = 0; i < rangeCount; i++) { - var range = cm.listSelections()[i]; - if (range.empty()) - cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0)); - else - cm.replaceRange(cm.getRange(range.from(), range.to()), range.from()); - } - cm.scrollIntoView(); - }); - }; - - - function sortLines(cm, caseSensitive) { - if (cm.isReadOnly()) return CodeMirror.Pass - var ranges = cm.listSelections(), toSort = [], selected; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (range.empty()) continue; - var from = range.from().line, to = range.to().line; - while (i < ranges.length - 1 && ranges[i + 1].from().line == to) - to = ranges[++i].to().line; - if (!ranges[i].to().ch) to--; - toSort.push(from, to); - } - if (toSort.length) selected = true; - else toSort.push(cm.firstLine(), cm.lastLine()); - - cm.operation(function() { - var ranges = []; - for (var i = 0; i < toSort.length; i += 2) { - var from = toSort[i], to = toSort[i + 1]; - var start = Pos(from, 0), end = Pos(to); - var lines = cm.getRange(start, end, false); - if (caseSensitive) - lines.sort(); - else - lines.sort(function(a, b) { - var au = a.toUpperCase(), bu = b.toUpperCase(); - if (au != bu) { a = au; b = bu; } - return a < b ? -1 : a == b ? 0 : 1; - }); - cm.replaceRange(lines, start, end); - if (selected) ranges.push({anchor: start, head: Pos(to + 1, 0)}); - } - if (selected) cm.setSelections(ranges, 0); - }); - } - - cmds.sortLines = function(cm) { sortLines(cm, true); }; - cmds.sortLinesInsensitive = function(cm) { sortLines(cm, false); }; - - cmds.nextBookmark = function(cm) { - var marks = cm.state.sublimeBookmarks; - if (marks) while (marks.length) { - var current = marks.shift(); - var found = current.find(); - if (found) { - marks.push(current); - return cm.setSelection(found.from, found.to); - } - } - }; - - cmds.prevBookmark = function(cm) { - var marks = cm.state.sublimeBookmarks; - if (marks) while (marks.length) { - marks.unshift(marks.pop()); - var found = marks[marks.length - 1].find(); - if (!found) - marks.pop(); - else - return cm.setSelection(found.from, found.to); - } - }; - - cmds.toggleBookmark = function(cm) { - var ranges = cm.listSelections(); - var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); - for (var i = 0; i < ranges.length; i++) { - var from = ranges[i].from(), to = ranges[i].to(); - var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to); - for (var j = 0; j < found.length; j++) { - if (found[j].sublimeBookmark) { - found[j].clear(); - for (var k = 0; k < marks.length; k++) - if (marks[k] == found[j]) - marks.splice(k--, 1); - break; - } - } - if (j == found.length) - marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false})); - } - }; - - cmds.clearBookmarks = function(cm) { - var marks = cm.state.sublimeBookmarks; - if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear(); - marks.length = 0; - }; - - cmds.selectBookmarks = function(cm) { - var marks = cm.state.sublimeBookmarks, ranges = []; - if (marks) for (var i = 0; i < marks.length; i++) { - var found = marks[i].find(); - if (!found) - marks.splice(i--, 0); - else - ranges.push({anchor: found.from, head: found.to}); - } - if (ranges.length) - cm.setSelections(ranges, 0); - }; - - function modifyWordOrSelection(cm, mod) { - cm.operation(function() { - var ranges = cm.listSelections(), indices = [], replacements = []; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (range.empty()) { indices.push(i); replacements.push(""); } - else replacements.push(mod(cm.getRange(range.from(), range.to()))); - } - cm.replaceSelections(replacements, "around", "case"); - for (var i = indices.length - 1, at; i >= 0; i--) { - var range = ranges[indices[i]]; - if (at && CodeMirror.cmpPos(range.head, at) > 0) continue; - var word = wordAt(cm, range.head); - at = word.from; - cm.replaceRange(mod(word.word), word.from, word.to); - } - }); - } - - cmds.smartBackspace = function(cm) { - if (cm.somethingSelected()) return CodeMirror.Pass; - - cm.operation(function() { - var cursors = cm.listSelections(); - var indentUnit = cm.getOption("indentUnit"); - - for (var i = cursors.length - 1; i >= 0; i--) { - var cursor = cursors[i].head; - var toStartOfLine = cm.getRange({line: cursor.line, ch: 0}, cursor); - var column = CodeMirror.countColumn(toStartOfLine, null, cm.getOption("tabSize")); - - // Delete by one character by default - var deletePos = cm.findPosH(cursor, -1, "char", false); - - if (toStartOfLine && !/\S/.test(toStartOfLine) && column % indentUnit == 0) { - var prevIndent = new Pos(cursor.line, - CodeMirror.findColumn(toStartOfLine, column - indentUnit, indentUnit)); - - // Smart delete only if we found a valid prevIndent location - if (prevIndent.ch != cursor.ch) deletePos = prevIndent; - } - - cm.replaceRange("", deletePos, cursor, "+delete"); - } - }); - }; - - cmds.delLineRight = function(cm) { - cm.operation(function() { - var ranges = cm.listSelections(); - for (var i = ranges.length - 1; i >= 0; i--) - cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete"); - cm.scrollIntoView(); - }); - }; - - cmds.upcaseAtCursor = function(cm) { - modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); }); - }; - cmds.downcaseAtCursor = function(cm) { - modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); }); - }; - - cmds.setSublimeMark = function(cm) { - if (cm.state.sublimeMark) cm.state.sublimeMark.clear(); - cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); - }; - cmds.selectToSublimeMark = function(cm) { - var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); - if (found) cm.setSelection(cm.getCursor(), found); - }; - cmds.deleteToSublimeMark = function(cm) { - var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); - if (found) { - var from = cm.getCursor(), to = found; - if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; } - cm.state.sublimeKilled = cm.getRange(from, to); - cm.replaceRange("", from, to); - } - }; - cmds.swapWithSublimeMark = function(cm) { - var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); - if (found) { - cm.state.sublimeMark.clear(); - cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); - cm.setCursor(found); - } - }; - cmds.sublimeYank = function(cm) { - if (cm.state.sublimeKilled != null) - cm.replaceSelection(cm.state.sublimeKilled, null, "paste"); - }; - - cmds.showInCenter = function(cm) { - var pos = cm.cursorCoords(null, "local"); - cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); - }; - - function getTarget(cm) { - var from = cm.getCursor("from"), to = cm.getCursor("to"); - if (CodeMirror.cmpPos(from, to) == 0) { - var word = wordAt(cm, from); - if (!word.word) return; - from = word.from; - to = word.to; - } - return {from: from, to: to, query: cm.getRange(from, to), word: word}; - } - - function findAndGoTo(cm, forward) { - var target = getTarget(cm); - if (!target) return; - var query = target.query; - var cur = cm.getSearchCursor(query, forward ? target.to : target.from); - - if (forward ? cur.findNext() : cur.findPrevious()) { - cm.setSelection(cur.from(), cur.to()); - } else { - cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0) - : cm.clipPos(Pos(cm.lastLine()))); - if (forward ? cur.findNext() : cur.findPrevious()) - cm.setSelection(cur.from(), cur.to()); - else if (target.word) - cm.setSelection(target.from, target.to); - } - }; - cmds.findUnder = function(cm) { findAndGoTo(cm, true); }; - cmds.findUnderPrevious = function(cm) { findAndGoTo(cm,false); }; - cmds.findAllUnder = function(cm) { - var target = getTarget(cm); - if (!target) return; - var cur = cm.getSearchCursor(target.query); - var matches = []; - var primaryIndex = -1; - while (cur.findNext()) { - matches.push({anchor: cur.from(), head: cur.to()}); - if (cur.from().line <= target.from.line && cur.from().ch <= target.from.ch) - primaryIndex++; - } - cm.setSelections(matches, primaryIndex); - }; - - - var keyMap = CodeMirror.keyMap; - keyMap.macSublime = { - "Cmd-Left": "goLineStartSmart", - "Shift-Tab": "indentLess", - "Shift-Ctrl-K": "deleteLine", - "Alt-Q": "wrapLines", - "Ctrl-Left": "goSubwordLeft", - "Ctrl-Right": "goSubwordRight", - "Ctrl-Alt-Up": "scrollLineUp", - "Ctrl-Alt-Down": "scrollLineDown", - "Cmd-L": "selectLine", - "Shift-Cmd-L": "splitSelectionByLine", - "Esc": "singleSelectionTop", - "Cmd-Enter": "insertLineAfter", - "Shift-Cmd-Enter": "insertLineBefore", - "Cmd-D": "selectNextOccurrence", - "Shift-Cmd-Space": "selectScope", - "Shift-Cmd-M": "selectBetweenBrackets", - "Cmd-M": "goToBracket", - "Cmd-Ctrl-Up": "swapLineUp", - "Cmd-Ctrl-Down": "swapLineDown", - "Cmd-/": "toggleCommentIndented", - "Cmd-J": "joinLines", - "Shift-Cmd-D": "duplicateLine", - "F9": "sortLines", - "Cmd-F9": "sortLinesInsensitive", - "F2": "nextBookmark", - "Shift-F2": "prevBookmark", - "Cmd-F2": "toggleBookmark", - "Shift-Cmd-F2": "clearBookmarks", - "Alt-F2": "selectBookmarks", - "Backspace": "smartBackspace", - "Cmd-K Cmd-K": "delLineRight", - "Cmd-K Cmd-U": "upcaseAtCursor", - "Cmd-K Cmd-L": "downcaseAtCursor", - "Cmd-K Cmd-Space": "setSublimeMark", - "Cmd-K Cmd-A": "selectToSublimeMark", - "Cmd-K Cmd-W": "deleteToSublimeMark", - "Cmd-K Cmd-X": "swapWithSublimeMark", - "Cmd-K Cmd-Y": "sublimeYank", - "Cmd-K Cmd-C": "showInCenter", - "Cmd-K Cmd-G": "clearBookmarks", - "Cmd-K Cmd-Backspace": "delLineLeft", - "Cmd-K Cmd-0": "unfoldAll", - "Cmd-K Cmd-J": "unfoldAll", - "Ctrl-Shift-Up": "addCursorToPrevLine", - "Ctrl-Shift-Down": "addCursorToNextLine", - "Cmd-F3": "findUnder", - "Shift-Cmd-F3": "findUnderPrevious", - "Alt-F3": "findAllUnder", - "Shift-Cmd-[": "fold", - "Shift-Cmd-]": "unfold", - "Cmd-I": "findIncremental", - "Shift-Cmd-I": "findIncrementalReverse", - "Cmd-H": "replace", - "F3": "findNext", - "Shift-F3": "findPrev", - "fallthrough": "macDefault" - }; - CodeMirror.normalizeKeyMap(keyMap.macSublime); - - keyMap.pcSublime = { - "Shift-Tab": "indentLess", - "Shift-Ctrl-K": "deleteLine", - "Alt-Q": "wrapLines", - "Ctrl-T": "transposeChars", - "Alt-Left": "goSubwordLeft", - "Alt-Right": "goSubwordRight", - "Ctrl-Up": "scrollLineUp", - "Ctrl-Down": "scrollLineDown", - "Ctrl-L": "selectLine", - "Shift-Ctrl-L": "splitSelectionByLine", - "Esc": "singleSelectionTop", - "Ctrl-Enter": "insertLineAfter", - "Shift-Ctrl-Enter": "insertLineBefore", - "Ctrl-D": "selectNextOccurrence", - "Shift-Ctrl-Space": "selectScope", - "Shift-Ctrl-M": "selectBetweenBrackets", - "Ctrl-M": "goToBracket", - "Shift-Ctrl-Up": "swapLineUp", - "Shift-Ctrl-Down": "swapLineDown", - "Ctrl-/": "toggleCommentIndented", - "Ctrl-J": "joinLines", - "Shift-Ctrl-D": "duplicateLine", - "F9": "sortLines", - "Ctrl-F9": "sortLinesInsensitive", - "F2": "nextBookmark", - "Shift-F2": "prevBookmark", - "Ctrl-F2": "toggleBookmark", - "Shift-Ctrl-F2": "clearBookmarks", - "Alt-F2": "selectBookmarks", - "Backspace": "smartBackspace", - "Ctrl-K Ctrl-K": "delLineRight", - "Ctrl-K Ctrl-U": "upcaseAtCursor", - "Ctrl-K Ctrl-L": "downcaseAtCursor", - "Ctrl-K Ctrl-Space": "setSublimeMark", - "Ctrl-K Ctrl-A": "selectToSublimeMark", - "Ctrl-K Ctrl-W": "deleteToSublimeMark", - "Ctrl-K Ctrl-X": "swapWithSublimeMark", - "Ctrl-K Ctrl-Y": "sublimeYank", - "Ctrl-K Ctrl-C": "showInCenter", - "Ctrl-K Ctrl-G": "clearBookmarks", - "Ctrl-K Ctrl-Backspace": "delLineLeft", - "Ctrl-K Ctrl-0": "unfoldAll", - "Ctrl-K Ctrl-J": "unfoldAll", - "Ctrl-Alt-Up": "addCursorToPrevLine", - "Ctrl-Alt-Down": "addCursorToNextLine", - "Ctrl-F3": "findUnder", - "Shift-Ctrl-F3": "findUnderPrevious", - "Alt-F3": "findAllUnder", - "Shift-Ctrl-[": "fold", - "Shift-Ctrl-]": "unfold", - "Ctrl-I": "findIncremental", - "Shift-Ctrl-I": "findIncrementalReverse", - "Ctrl-H": "replace", - "F3": "findNext", - "Shift-F3": "findPrev", - "fallthrough": "pcDefault" - }; - CodeMirror.normalizeKeyMap(keyMap.pcSublime); - - var mac = keyMap.default == keyMap.macDefault; - keyMap.sublime = mac ? keyMap.macSublime : keyMap.pcSublime; - }); - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - function doFold(cm, pos, options, force) { - if (options && options.call) { - var finder = options; - options = null; - } else { - var finder = getOption(cm, options, "rangeFinder"); - } - if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); - var minSize = getOption(cm, options, "minFoldSize"); - - function getRange(allowFolded) { - var range = finder(cm, pos); - if (!range || range.to.line - range.from.line < minSize) return null; - var marks = cm.findMarksAt(range.from); - for (var i = 0; i < marks.length; ++i) { - if (marks[i].__isFold && force !== "fold") { - if (!allowFolded) return null; - range.cleared = true; - marks[i].clear(); - } - } - return range; - } - - var range = getRange(true); - if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { - pos = CodeMirror.Pos(pos.line - 1, 0); - range = getRange(false); - } - if (!range || range.cleared || force === "unfold") return; - - var myWidget = makeWidget(cm, options); - CodeMirror.on(myWidget, "mousedown", function(e) { - myRange.clear(); - CodeMirror.e_preventDefault(e); - }); - var myRange = cm.markText(range.from, range.to, { - replacedWith: myWidget, - clearOnEnter: getOption(cm, options, "clearOnEnter"), - __isFold: true - }); - myRange.on("clear", function(from, to) { - CodeMirror.signal(cm, "unfold", cm, from, to); - }); - CodeMirror.signal(cm, "fold", cm, range.from, range.to); - } - - function makeWidget(cm, options) { - var widget = getOption(cm, options, "widget"); - if (typeof widget == "string") { - var text = document.createTextNode(widget); - widget = document.createElement("span"); - widget.appendChild(text); - widget.className = "CodeMirror-foldmarker"; - } else if (widget) { - widget = widget.cloneNode(true) - } - return widget; - } - - // Clumsy backwards-compatible interface - CodeMirror.newFoldFunction = function(rangeFinder, widget) { - return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; - }; - - // New-style interface - CodeMirror.defineExtension("foldCode", function(pos, options, force) { - doFold(this, pos, options, force); - }); - - CodeMirror.defineExtension("isFolded", function(pos) { - var marks = this.findMarksAt(pos); - for (var i = 0; i < marks.length; ++i) - if (marks[i].__isFold) return true; - }); - - CodeMirror.commands.toggleFold = function(cm) { - cm.foldCode(cm.getCursor()); - }; - CodeMirror.commands.fold = function(cm) { - cm.foldCode(cm.getCursor(), null, "fold"); - }; - CodeMirror.commands.unfold = function(cm) { - cm.foldCode(cm.getCursor(), null, "unfold"); - }; - CodeMirror.commands.foldAll = function(cm) { - cm.operation(function() { - for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) - cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); - }); - }; - CodeMirror.commands.unfoldAll = function(cm) { - cm.operation(function() { - for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) - cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); - }); - }; - - CodeMirror.registerHelper("fold", "combine", function() { - var funcs = Array.prototype.slice.call(arguments, 0); - return function(cm, start) { - for (var i = 0; i < funcs.length; ++i) { - var found = funcs[i](cm, start); - if (found) return found; - } - }; - }); - - CodeMirror.registerHelper("fold", "auto", function(cm, start) { - var helpers = cm.getHelpers(start, "fold"); - for (var i = 0; i < helpers.length; i++) { - var cur = helpers[i](cm, start); - if (cur) return cur; - } - }); - - var defaultOptions = { - rangeFinder: CodeMirror.fold.auto, - widget: "\u2194", - minFoldSize: 0, - scanUp: false, - clearOnEnter: true - }; - - CodeMirror.defineOption("foldOptions", null); - - function getOption(cm, options, name) { - if (options && options[name] !== undefined) - return options[name]; - var editorOptions = cm.options.foldOptions; - if (editorOptions && editorOptions[name] !== undefined) - return editorOptions[name]; - return defaultOptions[name]; - } - - CodeMirror.defineExtension("foldOption", function(options, name) { - return getOption(this, options, name); - }); - }); - - -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.registerHelper("fold", "brace", function(cm, start) { - var line = start.line, lineText = cm.getLine(line); - var tokenType; - - function findOpening(openCh) { - for (var at = start.ch, pass = 0;;) { - var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); - if (found == -1) { - if (pass == 1) break; - pass = 1; - at = lineText.length; - continue; - } - if (pass == 1 && found < start.ch) break; - tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); - if (!/^(comment|string)/.test(tokenType)) return found + 1; - at = found - 1; - } - } - - var startToken = "{", endToken = "}", startCh = findOpening("{"); - if (startCh == null) { - startToken = "[", endToken = "]"; - startCh = findOpening("["); - } - - if (startCh == null) return; - var count = 1, lastLine = cm.lastLine(), end, endCh; - outer: for (var i = line; i <= lastLine; ++i) { - var text = cm.getLine(i), pos = i == line ? startCh : 0; - for (;;) { - var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); - if (nextOpen < 0) nextOpen = text.length; - if (nextClose < 0) nextClose = text.length; - pos = Math.min(nextOpen, nextClose); - if (pos == text.length) break; - if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { - if (pos == nextOpen) ++count; - else if (!--count) { end = i; endCh = pos; break outer; } - } - ++pos; - } - } - if (end == null || line == end && endCh == startCh) return; - return {from: CodeMirror.Pos(line, startCh), - to: CodeMirror.Pos(end, endCh)}; - }); - - CodeMirror.registerHelper("fold", "import", function(cm, start) { - function hasImport(line) { - if (line < cm.firstLine() || line > cm.lastLine()) return null; - var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); - if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); - if (start.type != "keyword" || start.string != "import") return null; - // Now find closing semicolon, return its position - for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { - var text = cm.getLine(i), semi = text.indexOf(";"); - if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; - } - } - - var startLine = start.line, has = hasImport(startLine), prev; - if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1)) - return null; - for (var end = has.end;;) { - var next = hasImport(end.line + 1); - if (next == null) break; - end = next.end; - } - return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end}; - }); - - CodeMirror.registerHelper("fold", "include", function(cm, start) { - function hasInclude(line) { - if (line < cm.firstLine() || line > cm.lastLine()) return null; - var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); - if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); - if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; - } - - var startLine = start.line, has = hasInclude(startLine); - if (has == null || hasInclude(startLine - 1) != null) return null; - for (var end = startLine;;) { - var next = hasInclude(end + 1); - if (next == null) break; - ++end; - } - return {from: CodeMirror.Pos(startLine, has + 1), - to: cm.clipPos(CodeMirror.Pos(end))}; - }); - - }); - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { - return mode.blockCommentStart && mode.blockCommentEnd; - }, function(cm, start) { - var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; - if (!startToken || !endToken) return; - var line = start.line, lineText = cm.getLine(line); - - var startCh; - for (var at = start.ch, pass = 0;;) { - var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); - if (found == -1) { - if (pass == 1) return; - pass = 1; - at = lineText.length; - continue; - } - if (pass == 1 && found < start.ch) return; - if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && - (found == 0 || lineText.slice(found - endToken.length, found) == endToken || - !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { - startCh = found + startToken.length; - break; - } - at = found - 1; - } - - var depth = 1, lastLine = cm.lastLine(), end, endCh; - outer: for (var i = line; i <= lastLine; ++i) { - var text = cm.getLine(i), pos = i == line ? startCh : 0; - for (;;) { - var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); - if (nextOpen < 0) nextOpen = text.length; - if (nextClose < 0) nextClose = text.length; - pos = Math.min(nextOpen, nextClose); - if (pos == text.length) break; - if (pos == nextOpen) ++depth; - else if (!--depth) { end = i; endCh = pos; break outer; } - ++pos; - } - } - if (end == null || line == end && endCh == startCh) return; - return {from: CodeMirror.Pos(line, startCh), - to: CodeMirror.Pos(end, endCh)}; - }); - - }); - - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - var Pos = CodeMirror.Pos; - function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } - - var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; - var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; - var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); - - function Iter(cm, line, ch, range) { - this.line = line; this.ch = ch; - this.cm = cm; this.text = cm.getLine(line); - this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); - this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); - } - - function tagAt(iter, ch) { - var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); - return type && /\btag\b/.test(type); - } - - function nextLine(iter) { - if (iter.line >= iter.max) return; - iter.ch = 0; - iter.text = iter.cm.getLine(++iter.line); - return true; - } - function prevLine(iter) { - if (iter.line <= iter.min) return; - iter.text = iter.cm.getLine(--iter.line); - iter.ch = iter.text.length; - return true; - } - - function toTagEnd(iter) { - for (;;) { - var gt = iter.text.indexOf(">", iter.ch); - if (gt == -1) { if (nextLine(iter)) continue; else return; } - if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } - var lastSlash = iter.text.lastIndexOf("/", gt); - var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); - iter.ch = gt + 1; - return selfClose ? "selfClose" : "regular"; - } - } - function toTagStart(iter) { - for (;;) { - var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; - if (lt == -1) { if (prevLine(iter)) continue; else return; } - if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } - xmlTagStart.lastIndex = lt; - iter.ch = lt; - var match = xmlTagStart.exec(iter.text); - if (match && match.index == lt) return match; - } - } - - function toNextTag(iter) { - for (;;) { - xmlTagStart.lastIndex = iter.ch; - var found = xmlTagStart.exec(iter.text); - if (!found) { if (nextLine(iter)) continue; else return; } - if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } - iter.ch = found.index + found[0].length; - return found; - } - } - function toPrevTag(iter) { - for (;;) { - var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; - if (gt == -1) { if (prevLine(iter)) continue; else return; } - if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } - var lastSlash = iter.text.lastIndexOf("/", gt); - var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); - iter.ch = gt + 1; - return selfClose ? "selfClose" : "regular"; - } - } - - function findMatchingClose(iter, tag) { - var stack = []; - for (;;) { - var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); - if (!next || !(end = toTagEnd(iter))) return; - if (end == "selfClose") continue; - if (next[1]) { // closing tag - for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { - stack.length = i; - break; - } - if (i < 0 && (!tag || tag == next[2])) return { - tag: next[2], - from: Pos(startLine, startCh), - to: Pos(iter.line, iter.ch) - }; - } else { // opening tag - stack.push(next[2]); - } - } - } - function findMatchingOpen(iter, tag) { - var stack = []; - for (;;) { - var prev = toPrevTag(iter); - if (!prev) return; - if (prev == "selfClose") { toTagStart(iter); continue; } - var endLine = iter.line, endCh = iter.ch; - var start = toTagStart(iter); - if (!start) return; - if (start[1]) { // closing tag - stack.push(start[2]); - } else { // opening tag - for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { - stack.length = i; - break; - } - if (i < 0 && (!tag || tag == start[2])) return { - tag: start[2], - from: Pos(iter.line, iter.ch), - to: Pos(endLine, endCh) - }; - } - } - } - - CodeMirror.registerHelper("fold", "xml", function(cm, start) { - var iter = new Iter(cm, start.line, 0); - for (;;) { - var openTag = toNextTag(iter) - if (!openTag || iter.line != start.line) return - var end = toTagEnd(iter) - if (!end) return - if (!openTag[1] && end != "selfClose") { - var startPos = Pos(iter.line, iter.ch); - var endPos = findMatchingClose(iter, openTag[2]); - return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null - } - } - }); - CodeMirror.findMatchingTag = function(cm, pos, range) { - var iter = new Iter(cm, pos.line, pos.ch, range); - if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; - var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); - var start = end && toTagStart(iter); - if (!end || !start || cmp(iter, pos) > 0) return; - var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; - if (end == "selfClose") return {open: here, close: null, at: "open"}; - - if (start[1]) { // closing tag - return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; - } else { // opening tag - iter = new Iter(cm, to.line, to.ch, range); - return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; - } - }; - - CodeMirror.findEnclosingTag = function(cm, pos, range, tag) { - var iter = new Iter(cm, pos.line, pos.ch, range); - for (;;) { - var open = findMatchingOpen(iter, tag); - if (!open) break; - var forward = new Iter(cm, pos.line, pos.ch, range); - var close = findMatchingClose(forward, open.tag); - if (close) return {open: open, close: close}; - } - }; - - // Used by addon/edit/closetag.js - CodeMirror.scanForClosingTag = function(cm, pos, name, end) { - var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); - return findMatchingClose(iter, name); - }; - }); - - -/***/ }), -/* 26 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2), __webpack_require__(22)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror", "./foldcode"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { - if (old && old != CodeMirror.Init) { - cm.clearGutter(cm.state.foldGutter.options.gutter); - cm.state.foldGutter = null; - cm.off("gutterClick", onGutterClick); - cm.off("change", onChange); - cm.off("viewportChange", onViewportChange); - cm.off("fold", onFold); - cm.off("unfold", onFold); - cm.off("swapDoc", onChange); - } - if (val) { - cm.state.foldGutter = new State(parseOptions(val)); - updateInViewport(cm); - cm.on("gutterClick", onGutterClick); - cm.on("change", onChange); - cm.on("viewportChange", onViewportChange); - cm.on("fold", onFold); - cm.on("unfold", onFold); - cm.on("swapDoc", onChange); - } - }); - - var Pos = CodeMirror.Pos; - - function State(options) { - this.options = options; - this.from = this.to = 0; - } - - function parseOptions(opts) { - if (opts === true) opts = {}; - if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; - if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; - if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; - return opts; - } - - function isFolded(cm, line) { - var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)); - for (var i = 0; i < marks.length; ++i) - if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i]; - } - - function marker(spec) { - if (typeof spec == "string") { - var elt = document.createElement("div"); - elt.className = spec + " CodeMirror-guttermarker-subtle"; - return elt; - } else { - return spec.cloneNode(true); - } - } - - function updateFoldInfo(cm, from, to) { - var opts = cm.state.foldGutter.options, cur = from; - var minSize = cm.foldOption(opts, "minFoldSize"); - var func = cm.foldOption(opts, "rangeFinder"); - cm.eachLine(from, to, function(line) { - var mark = null; - if (isFolded(cm, cur)) { - mark = marker(opts.indicatorFolded); - } else { - var pos = Pos(cur, 0); - var range = func && func(cm, pos); - if (range && range.to.line - range.from.line >= minSize) - mark = marker(opts.indicatorOpen); - } - cm.setGutterMarker(line, opts.gutter, mark); - ++cur; - }); - } - - function updateInViewport(cm) { - var vp = cm.getViewport(), state = cm.state.foldGutter; - if (!state) return; - cm.operation(function() { - updateFoldInfo(cm, vp.from, vp.to); - }); - state.from = vp.from; state.to = vp.to; - } - - function onGutterClick(cm, line, gutter) { - var state = cm.state.foldGutter; - if (!state) return; - var opts = state.options; - if (gutter != opts.gutter) return; - var folded = isFolded(cm, line); - if (folded) folded.clear(); - else cm.foldCode(Pos(line, 0), opts.rangeFinder); - } - - function onChange(cm) { - var state = cm.state.foldGutter; - if (!state) return; - var opts = state.options; - state.from = state.to = 0; - clearTimeout(state.changeUpdate); - state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); - } - - function onViewportChange(cm) { - var state = cm.state.foldGutter; - if (!state) return; - var opts = state.options; - clearTimeout(state.changeUpdate); - state.changeUpdate = setTimeout(function() { - var vp = cm.getViewport(); - if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { - updateInViewport(cm); - } else { - cm.operation(function() { - if (vp.from < state.from) { - updateFoldInfo(cm, vp.from, state.from); - state.from = vp.from; - } - if (vp.to > state.to) { - updateFoldInfo(cm, state.to, vp.to); - state.to = vp.to; - } - }); - } - }, opts.updateViewportTimeSpan || 400); - } - - function onFold(cm, from) { - var state = cm.state.foldGutter; - if (!state) return; - var line = from.line; - if (line >= state.from && line < state.to) - updateFoldInfo(cm, line, line + 1); - } - }); - - -/***/ }), -/* 27 */ -/***/ (function(module, exports, __webpack_require__) { - - // CodeMirror, copyright (c) by Marijn Haverbeke and others - // Distributed under an MIT license: http://codemirror.net/LICENSE - - (function(mod) { - if (true) // CommonJS - mod(__webpack_require__(2)); - else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); - else // Plain browser env - mod(CodeMirror); - })(function(CodeMirror) { - "use strict"; - - CodeMirror.runMode = function(string, modespec, callback, options) { - var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); - var ie = /MSIE \d/.test(navigator.userAgent); - var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); - - if (callback.appendChild) { - var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; - var node = callback, col = 0; - node.innerHTML = ""; - callback = function(text, style) { - if (text == "\n") { - // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. - // Emitting a carriage return makes everything ok. - node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); - col = 0; - return; - } - var content = ""; - // replace tabs - for (var pos = 0;;) { - var idx = text.indexOf("\t", pos); - if (idx == -1) { - content += text.slice(pos); - col += text.length - pos; - break; - } else { - col += idx - pos; - content += text.slice(pos, idx); - var size = tabSize - col % tabSize; - col += size; - for (var i = 0; i < size; ++i) content += " "; - pos = idx + 1; - } - } - - if (style) { - var sp = node.appendChild(document.createElement("span")); - sp.className = "cm-" + style.replace(/ +/g, " cm-"); - sp.appendChild(document.createTextNode(content)); - } else { - node.appendChild(document.createTextNode(content)); - } - }; - } - - var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); - for (var i = 0, e = lines.length; i < e; ++i) { - if (i) callback("\n"); - var stream = new CodeMirror.StringStream(lines[i]); - if (!stream.string && mode.blankLine) mode.blankLine(state); - while (!stream.eol()) { - var style = mode.token(stream, state); - callback(stream.current(), style, i, stream.start, state); - stream.start = stream.pos; - } - } - }; - - }); - -/***/ }) -/******/ ]); \ No newline at end of file +var CodeMirror=function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=27)}([function(e,t,n){e.exports=function(){"use strict";var e=navigator.userAgent,t=navigator.platform,n=/gecko\/\d/i.test(e),r=/MSIE \d/.test(e),i=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(e),o=/Edge\/(\d+)/.exec(e),a=r||i||o,l=a&&(r?document.documentMode||6:+(o||i)[1]),s=!o&&/WebKit\//.test(e),c=s&&/Qt\/\d+\.\d+/.test(e),u=!o&&/Chrome\//.test(e),f=/Opera\//.test(e),d=/Apple Computer/.test(navigator.vendor),h=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(e),p=/PhantomJS/.test(e),m=!o&&/AppleWebKit/.test(e)&&/Mobile\/\w+/.test(e),g=/Android/.test(e),v=m||g||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(e),y=m||/Mac/.test(t),b=/\bCrOS\b/.test(e),x=/win/i.test(t),w=f&&e.match(/Version\/(\d*\.\d*)/);w&&(w=Number(w[1])),w&&w>=15&&(f=!1,s=!0);var k=y&&(c||f&&(null==w||w<12.11)),C=n||a&&l>=9;function S(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}var L,M=function(e,t){var n=e.className,r=S(t).exec(n);if(r){var i=n.slice(r.index+r[0].length);e.className=n.slice(0,r.index)+(i?r[1]+i:"")}};function T(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function A(e,t){return T(e).appendChild(t)}function O(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return a+(t-o);a+=l-o,a+=n-a%n,o=l+1}}m?B=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:a&&(B=function(e){try{e.select()}catch(e){}});var z=function(){this.id=null};function _(e,t){for(var n=0;n=t)return r+Math.min(a,t-i);if(i+=o-r,r=o+1,(i+=n-i%n)>=t)return r}}var $=[""];function G(e){for(;$.length<=e;)$.push(X($)+" ");return $[e]}function X(e){return e[e.length-1]}function Y(e,t){for(var n=[],r=0;r"€"&&(e.toUpperCase()!=e.toLowerCase()||Z.test(e))}function te(e,t){return t?!!(t.source.indexOf("\\w")>-1&&ee(e))||t.test(e):ee(e)}function ne(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}var re=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;function ie(e){return e.charCodeAt(0)>=768&&re.test(e)}function oe(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function le(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?me(n,le(e,n).text.length):function(e,t){var n=e.ch;return null==n||n>t?me(e.line,t):n<0?me(e.line,0):e}(t,le(e,t.line).text.length)}function Ce(e,t){for(var n=[],r=0;r=t:o.to>t);(r||(r=[])).push(new Me(a,o.from,s?null:o.to))}}return r}(n,i,a),s=function(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t);if(l||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var s=null==o.from||(a.inclusiveLeft?o.from<=t:o.from0&&l)for(var x=0;xt)&&(!n||Be(n,o.marker)<0)&&(n=o.marker)}return n}function _e(e,t,n,r,i){var o=le(e,t),a=Le&&o.markedSpans;if(a)for(var l=0;l=0&&f<=0||u<=0&&f>=0)&&(u<=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?ge(c.to,n)>=0:ge(c.to,n)>0)||u>=0&&(s.marker.inclusiveRight&&i.inclusiveLeft?ge(c.from,r)<=0:ge(c.from,r)<0)))return!0}}}function He(e){for(var t;t=Fe(e);)e=t.find(-1,!0).line;return e}function Ke(e,t){var n=le(e,t),r=He(n);return n==r?t:fe(r)}function je(e,t){if(t>e.lastLine())return t;var n,r=le(e,t);if(!Ue(e,r))return t;for(;n=We(r);)r=n.find(1,!0).line;return fe(r)+1}function Ue(e,t){var n=Le&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}var Xe=null;function Ye(e,t,n){var r;Xe=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Xe=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Xe=i)}return null!=r?r:Xe}var Je=function(){var e="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",t="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";var n=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,r=/[stwN]/,i=/[LRr]/,o=/[Lb1n]/,a=/[1n]/;function l(e,t,n){this.level=e,this.from=t,this.to=n}return function(s,c){var u,f="ltr"==c?"L":"R";if(0==s.length||"ltr"==c&&!n.test(s))return!1;for(var d=s.length,h=[],p=0;p-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function rt(e,t){var n=tt(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function lt(e){e.prototype.on=function(e,t){et(this,e,t)},e.prototype.off=function(e,t){nt(this,e,t)}}function st(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function ct(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function ut(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function ft(e){st(e),ct(e)}function dt(e){return e.target||e.srcElement}function ht(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),y&&e.ctrlKey&&1==t&&(t=3),t}var pt,mt,gt=function(){if(a&&l<9)return!1;var e=O("div");return"draggable"in e||"dragDrop"in e}();function vt(e){if(null==pt){var t=O("span","​");A(e,O("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(pt=t.offsetWidth<=1&&t.offsetHeight>2&&!(a&&l<8))}var n=pt?O("span","​"):O("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return n.setAttribute("cm-text",""),n}function yt(e){if(null!=mt)return mt;var t=A(e,document.createTextNode("AخA")),n=L(t,0,1).getBoundingClientRect(),r=L(t,1,2).getBoundingClientRect();return T(e),!(!n||n.left==n.right)&&(mt=r.right-n.right<3)}var bt,xt=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),a=o.indexOf("\r");-1!=a?(n.push(o.slice(0,a)),t+=a+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},wt=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},kt="oncopy"in(bt=O("div"))||(bt.setAttribute("oncopy","return;"),"function"==typeof bt.oncopy),Ct=null,St={},Lt={};function Mt(e){if("string"==typeof e&&Lt.hasOwnProperty(e))e=Lt[e];else if(e&&"string"==typeof e.name&&Lt.hasOwnProperty(e.name)){var t=Lt[e.name];"string"==typeof t&&(t={name:t}),(e=Q(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return Mt("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return Mt("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Tt(e,t){t=Mt(t);var n=St[t.name];if(!n)return Tt(e,"text/plain");var r=n(e,t);if(At.hasOwnProperty(t.name)){var i=At[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}var At={};function Ot(e,t){var n=At.hasOwnProperty(e)?At[e]:At[e]={};F(t,n)}function Nt(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function Et(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Pt(e,t,n){return!e.startState||e.startState(t,n)}var It=function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n};It.prototype.eol=function(){return this.pos>=this.string.length},It.prototype.sol=function(){return this.pos==this.lineStart},It.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},It.prototype.next=function(){if(this.post},It.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},It.prototype.skipToEnd=function(){this.pos=this.string.length},It.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},It.prototype.backUp=function(e){this.pos-=e},It.prototype.column=function(){return this.lastColumnPos0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e},o=this.string.substr(this.pos,e.length);if(i(o)==i(e))return!1!==t&&(this.pos+=e.length),!0},It.prototype.current=function(){return this.string.slice(this.start,this.pos)},It.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},It.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},It.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var Rt=function(e,t){this.state=e,this.lookAhead=t},Bt=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1};function Dt(e,t,n,r){var i=[e.state.modeGen],o={};Vt(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var a=n.state,l=function(r){n.baseTokens=i;var l=e.state.overlays[r],s=1,c=0;n.state=!0,Vt(e,t.text,l.mode,n,function(e,t){for(var n=s;ce&&i.splice(s,1,e,i[s+1],r),s+=2,c=Math.min(e,r)}if(t)if(l.opaque)i.splice(n,s-n,e,"overlay "+t),s=n+2;else for(;ne.options.maxHighlightLength&&Nt(e.doc.mode,r.state),o=Dt(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Wt(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new Bt(r,!0,t);var o=function(e,t,n){for(var r,i,o=e.doc,a=n?-1:t-(e.doc.mode.innerMode?1e3:100),l=t;l>a;--l){if(l<=o.first)return o.first;var s=le(o,l-1),c=s.stateAfter;if(c&&(!n||l+(c instanceof Rt?c.lookAhead:0)<=o.modeFrontier))return l;var u=W(s.text,null,e.options.tabSize);(null==i||r>u)&&(i=l-1,r=u)}return i}(e,t,n),a=o>r.first&&le(r,o-1).stateAfter,l=a?Bt.fromSaved(r,a,o):new Bt(r,Pt(r.mode),o);return r.iter(o,t,function(n){zt(e,n.text,l);var r=l.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}Bt.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},Bt.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},Bt.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},Bt.fromSaved=function(e,t,n){return t instanceof Rt?new Bt(e,Nt(e.mode,t.state),n,t.lookAhead):new Bt(e,Nt(e.mode,t),n)},Bt.prototype.save=function(e){var t=!1!==e?Nt(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new Rt(t,this.maxLookAhead):t};var Kt=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n};function jt(e,t,n,r){var i,o=e.doc,a=o.mode;t=ke(o,t);var l,s=le(o,t.line),c=Wt(e,t.line,n),u=new It(s.text,e.options.tabSize,c);for(r&&(l=[]);(r||u.pose.options.maxHighlightLength?(l=!1,a&&zt(e,t,r,f.pos),f.pos=t.length,s=null):s=Ut(Ht(n,f,r.state,d),o),d){var h=d[0].name;h&&(s="m-"+(s?h+" "+s:h))}if(!l||u!=s){for(;c1&&!/ /.test(e))return e;for(var n=t,r="",i=0;ic&&f.from<=c);d++);if(f.to>=u)return e(n,r,i,o,a,l,s);e(n,r.slice(0,f.to-c),i,o,null,l,s),o=null,r=r.slice(f.to-c),c=f.to}}}function tn(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function nn(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,l,s,c,u,f,d,h=i.length,p=0,m=1,g="",v=0;;){if(v==p){s=c=u=f=l="",d=null,v=1/0;for(var y=[],b=void 0,x=0;xp||k.collapsed&&w.to==p&&w.from==p)?(null!=w.to&&w.to!=p&&v>w.to&&(v=w.to,c=""),k.className&&(s+=" "+k.className),k.css&&(l=(l?l+";":"")+k.css),k.startStyle&&w.from==p&&(u+=" "+k.startStyle),k.endStyle&&w.to==v&&(b||(b=[])).push(k.endStyle,w.to),k.title&&!f&&(f=k.title),k.collapsed&&(!d||Be(d.marker,k)<0)&&(d=w)):w.from>p&&v>w.from&&(v=w.from)}if(b)for(var C=0;C=h)break;for(var L=Math.min(h,v);;){if(g){var M=p+g.length;if(!d){var T=M>L?g.slice(0,L-p):g;t.addToken(t,T,a?a+s:s,u,p+T.length==v?c:"",f,l)}if(M>=L){g=g.slice(L-p),p=L;break}p=M,u=""}g=i.slice(o,o=n[m++]),a=Yt(n[m++],t.cm.options)}}else for(var A=1;An)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}function Nn(e,t,n,r){return In(e,Pn(e,t),n,r)}function En(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&t2&&o.push((s.bottom+c.top)/2-n.top)}}o.push(n.bottom-n.top)}}(e,t.view,t.rect),t.hasHeights=!0),(o=function(e,t,n,r){var i,o=Dn(t.map,n,r),s=o.node,c=o.start,u=o.end,f=o.collapse;if(3==s.nodeType){for(var d=0;d<4;d++){for(;c&&ie(t.line.text.charAt(o.coverStart+c));)--c;for(;o.coverStart+u1}(e))return t;var n=screen.logicalXDPI/screen.deviceXDPI,r=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*n,right:t.right*n,top:t.top*r,bottom:t.bottom*r}}(e.display.measure,i))}else{var h;c>0&&(f=r="right"),i=e.options.lineWrapping&&(h=s.getClientRects()).length>1?h["right"==r?h.length-1:0]:s.getBoundingClientRect()}if(a&&l<9&&!c&&(!i||!i.left&&!i.right)){var p=s.parentNode.getClientRects()[0];i=p?{left:p.left,right:p.left+nr(e.display),top:p.top,bottom:p.bottom}:Bn}for(var m=i.top-t.rect.top,g=i.bottom-t.rect.top,v=(m+g)/2,y=t.view.measure.heights,b=0;bt)&&(i=(o=s-l)-1,t>=s&&(a="right")),null!=i){if(r=e[c+2],l==s&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;c&&e[c-2]==e[c-3]&&e[c-1].insertLeft;)r=e[2+(c-=3)],a="left";if("right"==n&&i==s-l)for(;c=0&&(n=e[i]).left==n.right;i--);return n}function Wn(e){if(e.measure&&(e.measure.cache={},e.measure.heights=null,e.rest))for(var t=0;t=r.text.length?(s=r.text.length,c="before"):s<=0&&(s=0,c="after"),!l)return a("before"==c?s-1:s,"before"==c);function u(e,t,n){var r=l[t],i=1==r.level;return a(n?e-1:e,i!=n)}var f=Ye(l,s,c),d=Xe,h=u(s,f,"before"==c);return null!=d&&(h.other=u(s,d,"before"!=c)),h}function Gn(e,t){var n=0;t=ke(e.doc,t),e.options.lineWrapping||(n=nr(e.display)*t.ch);var r=le(e.doc,t.line),i=qe(r)+Cn(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function Xn(e,t,n,r,i){var o=me(e,t,n);return o.xRel=i,r&&(o.outside=!0),o}function Yn(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return Xn(r.first,0,null,!0,-1);var i=de(r,n),o=r.first+r.size-1;if(i>o)return Xn(r.first+r.size-1,le(r,o).text.length,null,!0,1);t<0&&(t=0);for(var a=le(r,i);;){var l=er(e,a,i,t,n),s=ze(a,l.ch+(l.xRel>0?1:0));if(!s)return l;var c=s.find(1);if(c.line==i)return c;a=le(r,i=c.line)}}function Jn(e,t,n,r){r-=jn(t);var i=t.text.length,o=ae(function(t){return In(e,n,t-1).bottom<=r},i,0);return i=ae(function(t){return In(e,n,t).top>r},o,i),{begin:o,end:i}}function Qn(e,t,n,r){n||(n=Pn(e,t));var i=Un(e,t,In(e,n,r),"line").top;return Jn(e,t,n,i)}function Zn(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function er(e,t,n,r,i){i-=qe(t);var o=Pn(e,t),a=jn(t),l=0,s=t.text.length,c=!0,u=Qe(t,e.doc.direction);if(u){var f=(e.options.lineWrapping?function(e,t,n,r,i,o,a){var l=Jn(e,t,r,a),s=l.begin,c=l.end;/\s/.test(t.text.charAt(c-1))&&c--;for(var u=null,f=null,d=0;d=c||h.to<=s)){var p=1!=h.level,m=In(e,r,p?Math.min(c,h.to)-1:Math.max(s,h.from)).right,g=mg)&&(u=h,f=g)}}return u||(u=i[i.length-1]),u.fromc&&(u={from:u.from,to:c,level:u.level}),u}:function(e,t,n,r,i,o,a){var l=ae(function(l){var s=i[l],c=1!=s.level;return Zn($n(e,me(n,c?s.to:s.from,c?"before":"after"),"line",t,r),o,a,!0)},0,i.length-1),s=i[l];if(l>0){var c=1!=s.level,u=$n(e,me(n,c?s.from:s.to,c?"after":"before"),"line",t,r);Zn(u,o,a,!0)&&u.top>a&&(s=i[l-1])}return s})(e,t,n,o,u,r,i);c=1!=f.level,l=c?f.from:f.to-1,s=c?f.to:f.from-1}var d,h,p=null,m=null,g=ae(function(t){var n=In(e,o,t);return n.top+=a,n.bottom+=a,!!Zn(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(p=t,m=n),!0)},l,s),v=!1;if(m){var y=r-m.left=x.bottom}return g=oe(t.text,g,1),Xn(n,g,h,v,r-d)}function tr(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Rn){Rn=O("pre");for(var t=0;t<49;++t)Rn.appendChild(document.createTextNode("x")),Rn.appendChild(O("br"));Rn.appendChild(document.createTextNode("x"))}A(e.measure,Rn);var n=Rn.offsetHeight/50;return n>3&&(e.cachedTextHeight=n),T(e.measure),n||1}function nr(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=O("span","xxxxxxxxxx"),n=O("pre",[t]);A(e.measure,n);var r=t.getBoundingClientRect(),i=(r.right-r.left)/10;return i>2&&(e.cachedCharWidth=i),i||10}function rr(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a)n[e.options.gutters[a]]=o.offsetLeft+o.clientLeft+i,r[e.options.gutters[a]]=o.clientWidth;return{fixedPos:ir(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function ir(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function or(e){var t=tr(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/nr(e.display)-3);return function(i){if(Ue(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r=e.display.viewTo||l.to().linet||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}(m,n||0,null==r?d:r,function(e,t,i,f){var g="ltr"==i,v=h(e,g?"left":"right"),y=h(t-1,g?"right":"left"),b=null==n&&0==e,x=null==r&&t==d,w=0==f,k=!m||f==m.length-1;if(y.top-v.top<=3){var C=(c?b:x)&&w,S=(c?x:b)&&k,L=C?l:(g?v:y).left,M=S?s:(g?y:v).right;u(L,v.top,M-L,v.bottom)}else{var T,A,O,N;g?(T=c&&b&&w?l:v.left,A=c?s:p(e,i,"before"),O=c?l:p(t,i,"after"),N=c&&x&&k?s:y.right):(T=c?p(e,i,"before"):l,A=!c&&b&&w?s:v.right,O=!c&&x&&k?l:y.left,N=c?p(t,i,"after"):s),u(T,v.top,A-T,v.bottom),v.bottom0?t.blinker=setInterval(function(){return t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function mr(e){e.state.focused||(e.display.input.focus(),vr(e))}function gr(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,yr(e))},100)}function vr(e,t){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(rt(e,"focus",e,t),e.state.focused=!0,I(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),s&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),pr(e))}function yr(e,t){e.state.delayingBlurEvent||(e.state.focused&&(rt(e,"blur",e,t),e.state.focused=!1,M(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function br(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=0;r.005||u<-.005)&&(ue(i.line,o),xr(i.line),i.rest))for(var f=0;f=a&&(o=de(t,qe(le(t,s))-e.wrapper.clientHeight),a=s)}return{from:o,to:Math.max(a,o+1)}}function kr(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=ir(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;ao&&(t.bottom=t.top+o);var l=e.doc.height+Sn(n),s=t.topl-r;if(t.topi+o){var u=Math.min(t.top,(c?l:t.bottom)-o);u!=i&&(a.scrollTop=u)}var f=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft,d=Tn(e)-(e.options.fixedGutter?n.gutters.offsetWidth:0),h=t.right-t.left>d;return h&&(t.right=t.left+d),t.left<10?a.scrollLeft=0:t.leftd+f-3&&(a.scrollLeft=t.right+(h?0:10)-d),a}function Lr(e,t){null!=t&&(Ar(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Mr(e){Ar(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Tr(e,t,n){null==t&&null==n||Ar(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Ar(e){var t=e.curOp.scrollToPos;if(t){e.curOp.scrollToPos=null;var n=Gn(e,t.from),r=Gn(e,t.to);Or(e,n,r,t.margin)}}function Or(e,t,n,r){var i=Sr(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Tr(e,i.scrollLeft,i.scrollTop)}function Nr(e,t){Math.abs(e.doc.scrollTop-t)<2||(n||li(e,{top:t}),Er(e,t,!0),n&&li(e),ni(e,100))}function Er(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Pr(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,kr(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Ir(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Sn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Mn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}var Rr=function(e,t,n){this.cm=n;var r=this.vert=O("div",[O("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=O("div",[O("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),et(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),et(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,a&&l<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Rr.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Rr.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Rr.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Rr.prototype.zeroWidthHack=function(){var e=y&&!h?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new z,this.disableVert=new z},Rr.prototype.enableZeroWidthBar=function(e,t,n){e.style.pointerEvents="auto",t.set(1e3,function r(){var i=e.getBoundingClientRect(),o="vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1);o!=e?e.style.pointerEvents="none":t.set(1e3,r)})},Rr.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Br=function(){};function Dr(e,t){t||(t=Ir(e));var n=e.display.barWidth,r=e.display.barHeight;Fr(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&br(e),Fr(e,Ir(e)),n=e.display.barWidth,r=e.display.barHeight}function Fr(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}Br.prototype.update=function(){return{bottom:0,right:0}},Br.prototype.setScrollLeft=function(){},Br.prototype.setScrollTop=function(){},Br.prototype.clear=function(){};var Wr={native:Rr,null:Br};function zr(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&M(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new Wr[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),et(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?Pr(e,t):Nr(e,t)},e),e.display.scrollbars.addClass&&I(e.display.wrapper,e.display.scrollbars.addClass)}var _r=0;function Hr(e){var t;e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++_r},t=e.curOp,an?an.ops.push(t):t.ownsGroup=an={ops:[t],delayedCallbacks:[]}}function Kr(e){var t=e.curOp;!function(e,t){var n=e.ownsGroup;if(n)try{!function(e){var t=e.delayedCallbacks,n=0;do{for(;n=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ii(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function Ur(e){var t=e.cm,n=t.display;e.updatedDisplay&&br(t),e.barMeasure=Ir(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=Nn(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Mn(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Tn(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function Vr(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft1&&(a=!0)),null!=c.scrollLeft&&(Pr(e,c.scrollLeft),Math.abs(e.doc.scrollLeft-f)>1&&(a=!0)),!a)break}return i}(t,ke(r,e.scrollToPos.from),ke(r,e.scrollToPos.to),e.scrollToPos.margin);!function(e,t){if(!it(e,"scrollCursorIntoView")){var n=e.display,r=n.sizer.getBoundingClientRect(),i=null;if(t.top+r.top<0?i=!0:t.bottom+r.top>(window.innerHeight||document.documentElement.clientHeight)&&(i=!1),null!=i&&!p){var o=O("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-Cn(e.display))+"px;\n height: "+(t.bottom-t.top+Mn(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(o),o.scrollIntoView(i),e.display.lineSpace.removeChild(o)}}}(t,i)}var o=e.maybeHiddenMarkers,a=e.maybeUnhiddenMarkers;if(o)for(var l=0;lt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Le&&Ke(e.doc,t)i.viewFrom?Zr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)Zr(e);else if(t<=i.viewFrom){var o=ei(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):Zr(e)}else if(n>=i.viewTo){var a=ei(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):Zr(e)}else{var l=ei(e,t,t,-1),s=ei(e,n,n+r,1);l&&s?(i.view=i.view.slice(0,l.index).concat(on(e,l.lineN,s.lineN)).concat(i.view.slice(s.index)),i.viewTo+=r):Zr(e)}var c=i.externalMeasured;c&&(n=i.lineN&&t=r.viewTo)){var o=r.view[sr(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==_(a,n)&&a.push(n)}}}function Zr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function ei(e,t,n,r){var i,o=sr(e,t),a=e.display.view;if(!Le||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var l=e.display.viewFrom,s=0;s0){if(o==a.length-1)return null;i=l+a[o].size-t,o++}else i=l-t;t+=i,n+=i}for(;Ke(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function ti(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Wt(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var a=o.styles,l=o.text.length>e.options.maxHighlightLength?Nt(t.mode,r.state):null,s=Dt(e,o,r,!0);l&&(r.state=l),o.styles=s.styles;var c=o.styleClasses,u=s.classes;u?o.styleClasses=u:c&&(o.styleClasses=null);for(var f=!a||a.length!=o.styles.length||c!=u&&(!c||!u||c.bgClass!=u.bgClass||c.textClass!=u.textClass),d=0;!f&&dn)return ni(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&$r(e,function(){for(var t=0;t=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==ti(e))return!1;Cr(e)&&(Zr(e),t.dims=rr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),a=Math.min(i,t.visible.to+e.options.viewportMargin);n.viewFroma&&n.viewTo-a<20&&(a=Math.min(i,n.viewTo)),Le&&(o=Ke(e.doc,o),a=je(e.doc,a));var l=o!=n.viewFrom||a!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth;!function(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=on(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=on(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,sr(e,n)))),r.viewTo=n}(e,o,a),n.viewOffset=qe(le(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px";var c=ti(e);if(!l&&0==c&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var u=function(e){if(e.hasFocus())return null;var t=P();if(!t||!E(e.display.lineDiv,t))return null;var n={activeElt:t};if(window.getSelection){var r=window.getSelection();r.anchorNode&&r.extend&&E(e.display.lineDiv,r.anchorNode)&&(n.anchorNode=r.anchorNode,n.anchorOffset=r.anchorOffset,n.focusNode=r.focusNode,n.focusOffset=r.focusOffset)}return n}(e);return c>4&&(n.lineDiv.style.display="none"),function(e,t,n){var r=e.display,i=e.options.lineNumbers,o=r.lineDiv,a=o.firstChild;function l(t){var n=t.nextSibling;return s&&y&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var c=r.view,u=r.viewFrom,f=0;f-1&&(h=!1),un(e,d,u,n)),h&&(T(d.lineNumber),d.lineNumber.appendChild(document.createTextNode(pe(e.options,u)))),a=d.node.nextSibling}else{var p=vn(e,d,u,n);o.insertBefore(p,a)}u+=d.size}for(;a;)a=l(a)}(e,n.updateLineNumbers,t.dims),c>4&&(n.lineDiv.style.display=""),n.renderedView=n.view,function(e){if(e&&e.activeElt&&e.activeElt!=P()&&(e.activeElt.focus(),e.anchorNode&&E(document.body,e.anchorNode)&&E(document.body,e.focusNode))){var t=window.getSelection(),n=document.createRange();n.setEnd(e.anchorNode,e.anchorOffset),n.collapse(!1),t.removeAllRanges(),t.addRange(n),t.extend(e.focusNode,e.focusOffset)}}(u),T(n.cursorDiv),T(n.selectionDiv),n.gutters.style.height=n.sizer.style.minHeight=0,l&&(n.lastWrapHeight=t.wrapperHeight,n.lastWrapWidth=t.wrapperWidth,ni(e,400)),n.updateLineNumbers=null,!0}function ai(e,t){for(var n=t.viewport,r=!0;(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Tn(e)||(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Sn(e.display)-An(e),n.top)}),t.visible=wr(e.display,e.doc,n),!(t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)))&&oi(e,t);r=!1){br(e);var i=Ir(e);cr(e),Dr(e,i),ci(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function li(e,t){var n=new ii(e,t);if(oi(e,n)){br(e),ai(e,n);var r=Ir(e);cr(e),Dr(e,r),ci(e,r),n.finish()}}function si(e){var t=e.display.gutters.offsetWidth;e.display.sizer.style.marginLeft=t+"px"}function ci(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Mn(e)+"px"}function ui(e){var t=e.display.gutters,n=e.options.gutters;T(t);for(var r=0;r-1&&!e.lineNumbers&&(e.gutters=e.gutters.slice(0),e.gutters.splice(t,1))}ii.prototype.signal=function(e,t){at(e,t)&&this.events.push(arguments)},ii.prototype.finish=function(){for(var e=0;el.clientWidth,u=l.scrollHeight>l.clientHeight;if(i&&c||o&&u){if(o&&y&&s)e:for(var d=t.target,h=a.view;d!=l;d=d.parentNode)for(var p=0;p=0&&ge(e,r.to())<=0)return n}return-1};var yi=function(e,t){this.anchor=e,this.head=t};function bi(e,t){var n=e[t];e.sort(function(e,t){return ge(e.from(),t.from())}),t=_(e,n);for(var r=1;r=0){var a=xe(o.from(),i.from()),l=be(o.to(),i.to()),s=o.empty()?i.from()==i.head:o.from()==o.head;r<=t&&--t,e.splice(--r,2,new yi(s?l:a,s?a:l))}}return new vi(e,t)}function xi(e,t){return new vi([new yi(e,t||e)],0)}function wi(e){return e.text?me(e.from.line+e.text.length-1,X(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function ki(e,t){if(ge(e,t.from)<0)return e;if(ge(e,t.to)<=0)return wi(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=wi(t).ch-t.to.ch),me(n,r)}function Ci(e,t){for(var n=[],r=0;r1&&e.remove(l.line+1,p-1),e.insert(l.line+1,v)}sn(e,"change",e,t)}function Oi(e,t,n){!function e(r,i,o){if(r.linked)for(var a=0;al-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=function(e,t){return t?(Ri(e.done),X(e.done)):e.done.length&&!X(e.done).ranges?X(e.done):e.done.length>1&&!e.done[e.done.length-2].ranges?(e.done.pop(),X(e.done)):void 0}(i,i.lastOp==r)))a=X(o.changes),0==ge(t.from,t.to)&&0==ge(t.from,a.to)?a.to=wi(t):o.changes.push(Ii(e,t));else{var s=X(i.done);for(s&&s.ranges||Fi(e.sel,i.done),o={changes:[Ii(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=l,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||rt(e,"historyAdded")}function Di(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||function(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}(e,o,X(i.done),t))?i.done[i.done.length-1]=t:Fi(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&Ri(i.undone)}function Fi(e,t){var n=X(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Wi(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function zi(e){if(!e)return null;for(var t,n=0;n-1&&(X(l)[f]=c[f],delete c[f])}}}return r}function Ki(e,t,n,r){if(r){var i=e.anchor;if(n){var o=ge(t,i)<0;o!=ge(n,i)<0?(i=t,t=n):o!=ge(t,n)<0&&(t=n)}return new yi(i,t)}return new yi(n||t,t)}function ji(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),Gi(e,new vi([Ki(e.sel.primary(),t,n,i)],0),r)}function Ui(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:l.to>t.ch))){if(i&&(rt(s,"beforeCursorEnter"),s.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!s.atomic)continue;if(n){var c=s.find(r<0?1:-1),u=void 0;if((r<0?s.inclusiveRight:s.inclusiveLeft)&&(c=to(e,c,-r,c&&c.line==t.line?o:null)),c&&c.line==t.line&&(u=ge(c,n))&&(r<0?u<0:u>0))return Zi(e,c,t,r,i)}var f=s.find(r<0?-1:1);return(r<0?s.inclusiveLeft:s.inclusiveRight)&&(f=to(e,f,r,f.line==t.line?o:null)),f?Zi(e,f,t,r,i):null}}return t}function eo(e,t,n,r,i){var o=r||1,a=Zi(e,t,n,o,i)||!i&&Zi(e,t,n,o,!0)||Zi(e,t,n,-o,i)||!i&&Zi(e,t,n,-o,!0);return a||(e.cantEdit=!0,me(e.first,0))}function to(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?ke(e,me(t.line-1)):null:n>0&&t.ch==(r||le(e,t.line)).text.length?t.line0)){var u=[s,1],f=ge(c.from,l.from),d=ge(c.to,l.to);(f<0||!a.inclusiveLeft&&!f)&&u.push({from:c.from,to:l.from}),(d>0||!a.inclusiveRight&&!d)&&u.push({from:l.to,to:c.to}),i.splice.apply(i,u),s+=u.length-3}}return i}(e,t.from,t.to);if(r)for(var i=r.length-1;i>=0;--i)oo(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else oo(e,t)}}function oo(e,t){if(1!=t.text.length||""!=t.text[0]||0!=ge(t.from,t.to)){var n=Ci(e,t);Bi(e,t,n,e.cm?e.cm.curOp.id:NaN),so(e,t,n,Oe(e,t));var r=[];Oi(e,function(e,n){n||-1!=_(r,e.history)||(ho(e.history,t),r.push(e.history)),so(e,t,null,Oe(e,t))})}}function ao(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!r||n){for(var i,o=e.history,a=e.sel,l="undo"==t?o.done:o.undone,s="undo"==t?o.undone:o.done,c=0;c=0;--h){var p=d(h);if(p)return p.v}}}}function lo(e,t){if(0!=t&&(e.first+=t,e.sel=new vi(Y(e.sel.ranges,function(e){return new yi(me(e.anchor.line+t,e.anchor.ch),me(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){Jr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:me(o,le(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=se(e,t.from,t.to),n||(n=Ci(e,t)),e.cm?function(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,l=!1,s=o.line;e.options.lineWrapping||(s=fe(He(le(r,o.line))),r.iter(s,a.line+1,function(e){if(e==i.maxLine)return l=!0,!0})),r.sel.contains(t.from,t.to)>-1&&ot(e),Ai(r,t,n,or(e)),e.options.lineWrapping||(r.iter(s,o.line+t.text.length,function(e){var t=$e(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,l=!1)}),l&&(e.curOp.updateMaxLine=!0)),function(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=le(e,r).stateAfter;if(i&&(!(i instanceof Rt)||r+i.lookAhead1||!(this.children[0]instanceof mo))){var l=[];this.collapse(l),this.children=[new mo(l)],this.children[0].parent=this}},collapse:function(e){for(var t=0;t50){for(var a=i.lines.length%25+25,l=a;l10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=0;r0||0==a&&!1!==o.clearWhenEmpty)return o;if(o.replacedWith&&(o.collapsed=!0,o.widgetNode=N("span",[o.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||o.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(o.widgetNode.insertLeft=!0)),o.collapsed){if(_e(e,t.line,t,n,o)||t.line!=n.line&&_e(e,n.line,t,n,o))throw new Error("Inserting collapsed marker partially overlapping an existing one");Le=!0}o.addToHistory&&Bi(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var l,s=t.line,c=e.cm;if(e.iter(s,n.line+1,function(e){c&&o.collapsed&&!c.options.lineWrapping&&He(e)==c.display.maxLine&&(l=!0),o.collapsed&&s!=t.line&&ue(e,0),function(e,t){e.markedSpans=e.markedSpans?e.markedSpans.concat([t]):[t],t.marker.attachLine(e)}(e,new Me(o,s==t.line?t.ch:null,s==n.line?n.ch:null)),++s}),o.collapsed&&e.iter(t.line,n.line+1,function(t){Ue(e,t)&&ue(t,0)}),o.clearOnEnter&&et(o,"beforeCursorEnter",function(){return o.clear()}),o.readOnly&&(Se=!0,(e.history.done.length||e.history.undone.length)&&e.clearHistory()),o.collapsed&&(o.id=++bo,o.atomic=!0),c){if(l&&(c.curOp.updateMaxLine=!0),o.collapsed)Jr(c,t.line,n.line+1);else if(o.className||o.title||o.startStyle||o.endStyle||o.css)for(var u=t.line;u<=n.line;u++)Qr(c,u,"text");o.atomic&&Ji(c.doc),sn(c,"markerAdded",c,o)}return o}xo.prototype.clear=function(){if(!this.explicitlyCleared){var e=this.doc.cm,t=e&&!e.curOp;if(t&&Hr(e),at(this,"clear")){var n=this.find();n&&sn(this,"clear",n.from,n.to)}for(var r=null,i=null,o=0;oe.display.maxLineLength&&(e.display.maxLine=c,e.display.maxLineLength=u,e.display.maxLineChanged=!0)}null!=r&&e&&this.collapsed&&Jr(e,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,e&&Ji(e.doc)),e&&sn(e,"markerCleared",e,this,r,i),t&&Kr(e),this.parent&&this.parent.clear()}},xo.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=0;s--)io(this,r[s]);l?$i(this,l):this.cm&&Mr(this.cm)}),undo:Yr(function(){ao(this,"undo")}),redo:Yr(function(){ao(this,"redo")}),undoSelection:Yr(function(){ao(this,"undo",!0)}),redoSelection:Yr(function(){ao(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=ke(this,e),t=ke(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var a=o.markedSpans;if(a)for(var l=0;l=s.to||null==s.from&&i!=e.line||null!=s.from&&i==t.line&&s.from>=t.ch||n&&!n(s.marker)||r.push(s.marker.parent||s.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n}),ke(this,me(n,t))},indexFromPos:function(e){var t=(e=ke(this,e)).ch;if(e.linet&&(t=e.from),null!=e.to&&e.to-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var u=e.dataTransfer.getData("Text");if(u){var f;if(t.state.draggingText&&!t.state.draggingText.copy&&(f=t.listSelections()),Xi(t.doc,xi(n,n)),f)for(var d=0;d=0;t--)co(e.doc,"",r[t].from,r[t].to,"+delete");Mr(e)})}function $o(e,t,n){var r=oe(e.text,t+n,n);return r<0||r>e.text.length?null:r}function Go(e,t,n){var r=$o(e,t.ch,n);return null==r?null:new me(t.line,r,n<0?"after":"before")}function Xo(e,t,n,r,i){if(e){var o=Qe(n,t.doc.direction);if(o){var a,l=i<0?X(o):o[0],s=i<0==(1==l.level),c=s?"after":"before";if(l.level>0||"rtl"==t.doc.direction){var u=Pn(t,n);a=i<0?n.text.length-1:0;var f=In(t,u,a).top;a=ae(function(e){return In(t,u,e).top==f},i<0==(1==l.level)?l.from:l.to-1,a),"before"==c&&(a=$o(n,a,1))}else a=i<0?l.to:l.from;return new me(r,a,c)}}return new me(r,i<0?n.text.length:0,i<0?"before":"after")}Wo.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Wo.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Wo.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Wo.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Wo.default=y?Wo.macDefault:Wo.pcDefault;var Yo={selectAll:no,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),j)},killLine:function(e){return qo(e,function(t){if(t.empty()){var n=le(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line0)i=new me(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),me(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=le(e.doc,i.line-1).text;a&&(i=new me(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),me(i.line-1,a.length-1),i,"+transpose"))}n.push(new yi(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return $r(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r-1&&(ge((i=c.ranges[i]).from(),t)<0||t.xRel>0)&&(ge(i.to(),t)>0||t.xRel<0)?function(e,t,n,r){var i=e.display,o=!1,c=Gr(e,function(t){s&&(i.scroller.draggable=!1),e.state.draggingText=!1,nt(i.wrapper.ownerDocument,"mouseup",c),nt(i.wrapper.ownerDocument,"mousemove",u),nt(i.scroller,"dragstart",f),nt(i.scroller,"drop",c),o||(st(t),r.addNew||ji(e.doc,n,null,null,r.extend),s||a&&9==l?setTimeout(function(){i.wrapper.ownerDocument.body.focus(),i.input.focus()},20):i.input.focus())}),u=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},f=function(){return o=!0};s&&(i.scroller.draggable=!0),e.state.draggingText=c,c.copy=!r.moveOnDrag,i.scroller.dragDrop&&i.scroller.dragDrop(),et(i.wrapper.ownerDocument,"mouseup",c),et(i.wrapper.ownerDocument,"mousemove",u),et(i.scroller,"dragstart",f),et(i.scroller,"drop",c),gr(e),setTimeout(function(){return i.input.focus()},20)}(e,r,t,o):function(e,t,n,r){var i=e.display,o=e.doc;st(t);var a,l,s=o.sel,c=s.ranges;if(r.addNew&&!r.extend?(l=o.sel.contains(n),a=l>-1?c[l]:new yi(n,n)):(a=o.sel.primary(),l=o.sel.primIndex),"rectangle"==r.unit)r.addNew||(a=new yi(n,n)),n=lr(e,t,!0,!0),l=-1;else{var u=da(e,n,r.unit);a=r.extend?Ki(a,u.anchor,u.head,r.extend):u}r.addNew?-1==l?(l=c.length,Gi(o,bi(c.concat([a]),l),{scroll:!1,origin:"*mouse"})):c.length>1&&c[l].empty()&&"char"==r.unit&&!r.extend?(Gi(o,bi(c.slice(0,l).concat(c.slice(l+1)),0),{scroll:!1,origin:"*mouse"}),s=o.sel):Vi(o,l,a,U):(l=0,Gi(o,new vi([a],0),U),s=o.sel);var f=n;function d(t){if(0!=ge(f,t))if(f=t,"rectangle"==r.unit){for(var i=[],c=e.options.tabSize,u=W(le(o,n.line).text,n.ch,c),d=W(le(o,t.line).text,t.ch,c),h=Math.min(u,d),p=Math.max(u,d),m=Math.min(n.line,t.line),g=Math.min(e.lastLine(),Math.max(n.line,t.line));m<=g;m++){var v=le(o,m).text,y=q(v,h,c);h==p?i.push(new yi(me(m,y),me(m,y))):v.length>y&&i.push(new yi(me(m,y),me(m,q(v,p,c))))}i.length||i.push(new yi(n,n)),Gi(o,bi(s.ranges.slice(0,l).concat(i),l),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var b,x=a,w=da(e,t,r.unit),k=x.anchor;ge(w.anchor,k)>0?(b=w.head,k=xe(x.from(),w.anchor)):(b=w.anchor,k=be(x.to(),w.head));var C=s.ranges.slice(0);C[l]=function(e,t){var n=t.anchor,r=t.head,i=le(e.doc,n.line);if(0==ge(n,r)&&n.sticky==r.sticky)return t;var o=Qe(i);if(!o)return t;var a=Ye(o,n.ch,n.sticky),l=o[a];if(l.from!=n.ch&&l.to!=n.ch)return t;var s,c=a+(l.from==n.ch==(1!=l.level)?0:1);if(0==c||c==o.length)return t;if(r.line!=n.line)s=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var u=Ye(o,r.ch,r.sticky),f=u-a||(r.ch-n.ch)*(1==l.level?-1:1);s=u==c-1||u==c?f<0:f>0}var d=o[c+(s?-1:0)],h=s==(1==d.level),p=h?d.from:d.to,m=h?"after":"before";return n.ch==p&&n.sticky==m?t:new yi(new me(n.line,p,m),r)}(e,new yi(ke(o,k),b)),Gi(o,bi(C,l),U)}}var h=i.wrapper.getBoundingClientRect(),p=0;function m(t){e.state.selectingText=!1,p=1/0,st(t),i.input.focus(),nt(i.wrapper.ownerDocument,"mousemove",g),nt(i.wrapper.ownerDocument,"mouseup",v),o.history.lastSelOrigin=null}var g=Gr(e,function(t){0!==t.buttons&&ht(t)?function t(n){var a=++p,l=lr(e,n,!0,"rectangle"==r.unit);if(l)if(0!=ge(l,f)){e.curOp.focus=P(),d(l);var s=wr(i,o);(l.line>=s.to||l.lineh.bottom?20:0;c&&setTimeout(Gr(e,function(){p==a&&(i.scroller.scrollTop+=c,t(n))}),50)}}(t):m(t)}),v=Gr(e,m);e.state.selectingText=v,et(i.wrapper.ownerDocument,"mousemove",g),et(i.wrapper.ownerDocument,"mouseup",v)}(e,r,t,o)}(t,r,o,e):dt(e)==n.scroller&&st(e):2==i?(r&&ji(t.doc,r),setTimeout(function(){return n.input.focus()},20)):3==i&&(C?ma(t,e):gr(t)))}}function da(e,t,n){if("char"==n)return new yi(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new yi(me(t.line,0),ke(e.doc,me(t.line+1,0)));var r=n(e,t);return new yi(r.from,r.to)}function ha(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(t){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&st(t);var a=e.display,l=a.lineDiv.getBoundingClientRect();if(o>l.bottom||!at(e,n))return ut(t);o-=l.top-a.viewOffset;for(var s=0;s=i){var u=de(e.doc,o),f=e.options.gutters[s];return rt(e,n,e,u,f,t),ut(t)}}}function pa(e,t){return ha(e,t,"gutterClick",!0)}function ma(e,t){kn(e.display,t)||function(e,t){return!!at(e,"gutterContextMenu")&&ha(e,t,"gutterContextMenu",!1)}(e,t)||it(e,t,"contextmenu")||e.display.input.onContextMenu(t)}function ga(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),_n(e)}ua.prototype.compare=function(e,t,n){return this.time+400>e&&0==ge(t,this.pos)&&n==this.button};var va={toString:function(){return"CodeMirror.Init"}},ya={},ba={};function xa(e){ui(e),Jr(e),kr(e)}function wa(e,t,n){var r=n&&n!=va;if(!t!=!r){var i=e.display.dragFunctions,o=t?et:nt;o(e.display.scroller,"dragstart",i.start),o(e.display.scroller,"dragenter",i.enter),o(e.display.scroller,"dragover",i.over),o(e.display.scroller,"dragleave",i.leave),o(e.display.scroller,"drop",i.drop)}}function ka(e){e.options.lineWrapping?(I(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(M(e.display.wrapper,"CodeMirror-wrap"),Ge(e)),ar(e),Jr(e),_n(e),setTimeout(function(){return Dr(e)},100)}function Ca(e,t){var r=this;if(!(this instanceof Ca))return new Ca(e,t);this.options=t=t?F(t):{},F(ya,t,!1),fi(t);var i=t.value;"string"==typeof i&&(i=new Mo(i,t.mode,null,t.lineSeparator,t.direction)),this.doc=i;var o=new Ca.inputStyles[t.inputStyle](this),c=this.display=new function(e,t,r){var i=this;this.input=r,i.scrollbarFiller=O("div",null,"CodeMirror-scrollbar-filler"),i.scrollbarFiller.setAttribute("cm-not-content","true"),i.gutterFiller=O("div",null,"CodeMirror-gutter-filler"),i.gutterFiller.setAttribute("cm-not-content","true"),i.lineDiv=N("div",null,"CodeMirror-code"),i.selectionDiv=O("div",null,null,"position: relative; z-index: 1"),i.cursorDiv=O("div",null,"CodeMirror-cursors"),i.measure=O("div",null,"CodeMirror-measure"),i.lineMeasure=O("div",null,"CodeMirror-measure"),i.lineSpace=N("div",[i.measure,i.lineMeasure,i.selectionDiv,i.cursorDiv,i.lineDiv],null,"position: relative; outline: none");var o=N("div",[i.lineSpace],"CodeMirror-lines");i.mover=O("div",[o],null,"position: relative"),i.sizer=O("div",[i.mover],"CodeMirror-sizer"),i.sizerWidth=null,i.heightForcer=O("div",null,null,"position: absolute; height: "+H+"px; width: 1px;"),i.gutters=O("div",null,"CodeMirror-gutters"),i.lineGutter=null,i.scroller=O("div",[i.sizer,i.heightForcer,i.gutters],"CodeMirror-scroll"),i.scroller.setAttribute("tabIndex","-1"),i.wrapper=O("div",[i.scrollbarFiller,i.gutterFiller,i.scroller],"CodeMirror"),a&&l<8&&(i.gutters.style.zIndex=-1,i.scroller.style.paddingRight=0),s||n&&v||(i.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(i.wrapper):e(i.wrapper)),i.viewFrom=i.viewTo=t.first,i.reportedViewFrom=i.reportedViewTo=t.first,i.view=[],i.renderedView=null,i.externalMeasured=null,i.viewOffset=0,i.lastWrapHeight=i.lastWrapWidth=0,i.updateLineNumbers=null,i.nativeBarWidth=i.barHeight=i.barWidth=0,i.scrollbarsClipped=!1,i.lineNumWidth=i.lineNumInnerWidth=i.lineNumChars=null,i.alignWidgets=!1,i.cachedCharWidth=i.cachedTextHeight=i.cachedPaddingH=null,i.maxLine=null,i.maxLineLength=0,i.maxLineChanged=!1,i.wheelDX=i.wheelDY=i.wheelStartX=i.wheelStartY=null,i.shift=!1,i.selForContextMenu=null,i.activeTouch=null,r.init(i)}(e,i,o);for(var u in c.wrapper.CodeMirror=this,ui(this),ga(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),zr(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new z,keySeq:null,specialChars:null},t.autofocus&&!v&&c.input.focus(),a&&l<11&&setTimeout(function(){return r.display.input.reset(!0)},20),function(e){var t=e.display;et(t.scroller,"mousedown",Gr(e,fa)),et(t.scroller,"dblclick",a&&l<11?Gr(e,function(t){if(!it(e,t)){var n=lr(e,t);if(n&&!pa(e,t)&&!kn(e.display,t)){st(t);var r=e.findWordAt(n);ji(e.doc,r.anchor,r.head)}}}):function(t){return it(e,t)||st(t)}),C||et(t.scroller,"contextmenu",function(t){return ma(e,t)});var n,r={end:0};function i(){t.activeTouch&&(n=setTimeout(function(){return t.activeTouch=null},1e3),(r=t.activeTouch).end=+new Date)}function o(e,t){if(null==t.left)return!0;var n=t.left-e.left,r=t.top-e.top;return n*n+r*r>400}et(t.scroller,"touchstart",function(i){if(!it(e,i)&&!function(e){if(1!=e.touches.length)return!1;var t=e.touches[0];return t.radiusX<=1&&t.radiusY<=1}(i)&&!pa(e,i)){t.input.ensurePolled(),clearTimeout(n);var o=+new Date;t.activeTouch={start:o,moved:!1,prev:o-r.end<=300?r:null},1==i.touches.length&&(t.activeTouch.left=i.touches[0].pageX,t.activeTouch.top=i.touches[0].pageY)}}),et(t.scroller,"touchmove",function(){t.activeTouch&&(t.activeTouch.moved=!0)}),et(t.scroller,"touchend",function(n){var r=t.activeTouch;if(r&&!kn(t,n)&&null!=r.left&&!r.moved&&new Date-r.start<300){var a,l=e.coordsChar(t.activeTouch,"page");a=!r.prev||o(r,r.prev)?new yi(l,l):!r.prev.prev||o(r,r.prev.prev)?e.findWordAt(l):new yi(me(l.line,0),ke(e.doc,me(l.line+1,0))),e.setSelection(a.anchor,a.head),e.focus(),st(n)}i()}),et(t.scroller,"touchcancel",i),et(t.scroller,"scroll",function(){t.scroller.clientHeight&&(Nr(e,t.scroller.scrollTop),Pr(e,t.scroller.scrollLeft,!0),rt(e,"scroll",e))}),et(t.scroller,"mousewheel",function(t){return gi(e,t)}),et(t.scroller,"DOMMouseScroll",function(t){return gi(e,t)}),et(t.wrapper,"scroll",function(){return t.wrapper.scrollTop=t.wrapper.scrollLeft=0}),t.dragFunctions={enter:function(t){it(e,t)||ft(t)},over:function(t){it(e,t)||(function(e,t){var n=lr(e,t);if(n){var r=document.createDocumentFragment();fr(e,n,r),e.display.dragCursor||(e.display.dragCursor=O("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),e.display.lineSpace.insertBefore(e.display.dragCursor,e.display.cursorDiv)),A(e.display.dragCursor,r)}}(e,t),ft(t))},start:function(t){return function(e,t){if(a&&(!e.state.draggingText||+new Date-To<100))ft(t);else if(!it(e,t)&&!kn(e.display,t)&&(t.dataTransfer.setData("Text",e.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!d)){var n=O("img",null,null,"position: fixed; left: 0; top: 0;");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",f&&(n.width=n.height=1,e.display.wrapper.appendChild(n),n._top=n.offsetTop),t.dataTransfer.setDragImage(n,0,0),f&&n.parentNode.removeChild(n)}}(e,t)},drop:Gr(e,Ao),leave:function(t){it(e,t)||Oo(e)}};var s=t.input.getField();et(s,"keyup",function(t){return aa.call(e,t)}),et(s,"keydown",Gr(e,oa)),et(s,"keypress",Gr(e,la)),et(s,"focus",function(t){return vr(e,t)}),et(s,"blur",function(t){return yr(e,t)})}(this),Po(),Hr(this),this.curOp.forceUpdate=!0,Ni(this,i),t.autofocus&&!v||this.hasFocus()?setTimeout(D(vr,this),20):yr(this),ba)ba.hasOwnProperty(u)&&ba[u](r,t[u],va);Cr(this),t.finishInit&&t.finishInit(this);for(var h=0;h150)){if(!r)return;n="prev"}}else c=0,n="not";"prev"==n?c=t>o.first?W(le(o,t-1).text,null,a):0:"add"==n?c=s+e.options.indentUnit:"subtract"==n?c=s-e.options.indentUnit:"number"==typeof n&&(c=s+n),c=Math.max(0,c);var f="",d=0;if(e.options.indentWithTabs)for(var h=Math.floor(c/a);h;--h)d+=a,f+="\t";if(d1)if(Ma&&Ma.text.join("\n")==t){if(r.ranges.length%Ma.text.length==0){c=[];for(var u=0;u=0;f--){var d=r.ranges[f],h=d.from(),p=d.to();d.empty()&&(n&&n>0?h=me(h.line,h.ch-n):e.state.overwrite&&!l?p=me(p.line,Math.min(le(o,p.line).text.length,p.ch+X(s).length)):Ma&&Ma.lineWise&&Ma.text.join("\n")==t&&(h=p=me(h.line,0))),a=e.curOp.updateInput;var m={from:h,to:p,text:c?c[f%c.length]:s,origin:i||(l?"paste":e.state.cutIncoming?"cut":"+input")};io(e.doc,m),sn(e,"inputRead",e,m)}t&&!l&&Na(e,t),Mr(e),e.curOp.updateInput=a,e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=!1}function Oa(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||$r(t,function(){return Aa(t,n,0,null,"paste")}),!0}function Na(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var l=0;l-1){a=La(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(le(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=La(e,i.head.line,"smart"));a&&sn(e,"electricInput",e,i.head.line)}}}function Ea(e){for(var t=[],n=[],r=0;r=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=Ye(i,n.ch,n.sticky),a=i[o];if("ltr"==e.doc.direction&&a.level%2==0&&(r>0?a.to>n.ch:a.from=a.from&&d>=u.begin)){var h=f?"before":"after";return new me(n.line,d,h)}}var p=function(e,t,r){for(var o=function(e,t){return t?new me(n.line,s(e,1),"before"):new me(n.line,e,"after")};e>=0&&e0==(1!=a.level),c=l?r.begin:s(r.end,-1);if(a.from<=c&&c0?u.end:s(u.begin,-1);return null==g||r>0&&g==t.text.length||!(m=p(r>0?0:i.length-1,r,c(g)))?null:m}(e.cm,l,t,n):Go(l,t,n))){if(r||((a=t.line+n)=e.first+e.size||(t=new me(a,t.ch,t.sticky),!(l=le(e,a)))))return!1;t=Xo(i,e.cm,l,t.line,n)}else t=o;return!0}if("char"==r)s();else if("column"==r)s(!0);else if("word"==r||"group"==r)for(var c=null,u="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),d=!0;!(n<0)||s(!d);d=!1){var h=l.text.charAt(t.ch)||"\n",p=te(h,f)?"w":u&&"\n"==h?"n":!u||/\s/.test(h)?null:"p";if(!u||d||p||(p="s"),c&&c!=p){n<0&&(n=1,s(),t.sticky="after");break}if(p&&(c=p),n>0&&!s(!d))break}var m=eo(e,t,o,a,!0);return ve(o,m)&&(m.hitSide=!0),m}function Ba(e,t,n,r){var i,o,a=e.doc,l=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),c=Math.max(s-.5*tr(e.display),3);i=(n>0?t.bottom:t.top)+n*c}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(;(o=Yn(e,l,i)).outside;){if(n<0?i<=0:i>=a.height){o.hitSide=!0;break}i+=5*n}return o}var Da=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new z,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};function Fa(e,t){var n=En(e,t.line);if(!n||n.hidden)return null;var r=le(e.doc,t.line),i=On(n,r,t.line),o=Qe(r,e.doc.direction),a="left";if(o){var l=Ye(o,t.ch);a=l%2?"right":"left"}var s=Dn(i.map,t.ch,a);return s.offset="right"==s.collapse?s.end:s.start,s}function Wa(e,t){return t&&(e.bad=!0),e}function za(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Wa(e.clipPos(me(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i=t.display.viewTo||o.line=t.display.viewFrom&&Fa(t,i)||{node:s[0].measure.map[2],offset:0},u=o.liner.firstLine()&&(a=me(a.line-1,le(r.doc,a.line-1).length)),l.ch==le(r.doc,l.line).text.length&&l.linei.viewTo-1)return!1;a.line==i.viewFrom||0==(e=sr(r,a.line))?(t=fe(i.view[0].line),n=i.view[0].node):(t=fe(i.view[e].line),n=i.view[e-1].node.nextSibling);var s,c,u=sr(r,l.line);if(u==i.view.length-1?(s=i.viewTo-1,c=i.lineDiv.lastChild):(s=fe(i.view[u+1].line)-1,c=i.view[u+1].node.previousSibling),!n)return!1;for(var f=r.doc.splitLines(function(e,t,n,r,i){var o="",a=!1,l=e.doc.lineSeparator(),s=!1;function c(){a&&(o+=l,s&&(o+=l),a=s=!1)}function u(e){e&&(c(),o+=e)}function f(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void u(n);var o,d=t.getAttribute("cm-marker");if(d){var h=e.findMarks(me(r,0),me(i+1,0),(g=+d,function(e){return e.id==g}));return void(h.length&&(o=h[0].find(0))&&u(se(e.doc,o.from,o.to).join(l)))}if("false"==t.getAttribute("contenteditable"))return;var p=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;p&&c();for(var m=0;m1&&d.length>1;)if(X(f)==X(d))f.pop(),d.pop(),s--;else{if(f[0]!=d[0])break;f.shift(),d.shift(),t++}for(var h=0,p=0,m=f[0],g=d[0],v=Math.min(m.length,g.length);ha.ch&&y.charCodeAt(y.length-p-1)==b.charCodeAt(b.length-p-1);)h--,p++;f[f.length-1]=y.slice(0,y.length-p).replace(/^\u200b+/,""),f[0]=f[0].slice(h).replace(/\u200b+$/,"");var w=me(t,h),k=me(s,d.length?X(d).length-p:0);return f.length>1||f[0]||ge(w,k)?(co(r.doc,f,w,k,"+input"),!0):void 0},Da.prototype.ensurePolled=function(){this.forceCompositionEnd()},Da.prototype.reset=function(){this.forceCompositionEnd()},Da.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},Da.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},Da.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||$r(this.cm,function(){return Jr(e.cm)})},Da.prototype.setUneditable=function(e){e.contentEditable="false"},Da.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||Gr(this.cm,Aa)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},Da.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},Da.prototype.onContextMenu=function(){},Da.prototype.resetPosition=function(){},Da.prototype.needsContentAttribute=!0;var Ha=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new z,this.hasSelection=!1,this.composing=null};Ha.prototype.init=function(e){var t=this,n=this,r=this.cm;this.createField(e);var i=this.textarea;function o(e){if(!it(r,e)){if(r.somethingSelected())Ta({lineWise:!1,text:r.getSelections()});else{if(!r.options.lineWiseCopyCut)return;var t=Ea(r);Ta({lineWise:!0,text:t.text}),"cut"==e.type?r.setSelections(t.ranges,null,j):(n.prevInput="",i.value=t.text.join("\n"),B(i))}"cut"==e.type&&(r.state.cutIncoming=!0)}}e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),m&&(i.style.width="0px"),et(i,"input",function(){a&&l>=9&&t.hasSelection&&(t.hasSelection=null),n.poll()}),et(i,"paste",function(e){it(r,e)||Oa(e,r)||(r.state.pasteIncoming=!0,n.fastPoll())}),et(i,"cut",o),et(i,"copy",o),et(e.scroller,"paste",function(t){kn(e,t)||it(r,t)||(r.state.pasteIncoming=!0,n.focus())}),et(e.lineSpace,"selectstart",function(t){kn(e,t)||st(t)}),et(i,"compositionstart",function(){var e=r.getCursor("from");n.composing&&n.composing.range.clear(),n.composing={start:e,range:r.markText(e,r.getCursor("to"),{className:"CodeMirror-composing"})}}),et(i,"compositionend",function(){n.composing&&(n.poll(),n.composing.range.clear(),n.composing=null)})},Ha.prototype.createField=function(e){this.wrapper=Ia(),this.textarea=this.wrapper.firstChild},Ha.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=ur(e);if(e.options.moveInputWithCursor){var i=$n(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},Ha.prototype.showSelection=function(e){var t=this.cm,n=t.display;A(n.cursorDiv,e.cursors),A(n.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Ha.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&B(this.textarea),a&&l>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",a&&l>=9&&(this.hasSelection=null))}},Ha.prototype.getField=function(){return this.textarea},Ha.prototype.supportsTouch=function(){return!1},Ha.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!v||P()!=this.textarea))try{this.textarea.focus()}catch(e){}},Ha.prototype.blur=function(){this.textarea.blur()},Ha.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Ha.prototype.receivedFocus=function(){this.slowPoll()},Ha.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},Ha.prototype.fastPoll=function(){var e=!1,t=this;t.pollingFast=!0,t.polling.set(20,function n(){var r=t.poll();r||e?(t.pollingFast=!1,t.slowPoll()):(e=!0,t.polling.set(60,n))})},Ha.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||wt(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(a&&l>=9&&this.hasSelection===i||y&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var s=0,c=Math.min(r.length,i.length);s1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Ha.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Ha.prototype.onKeyPress=function(){a&&l>=9&&(this.hasSelection=null),this.fastPoll()},Ha.prototype.onContextMenu=function(e){var t=this,n=t.cm,r=n.display,i=t.textarea,o=lr(n,e),c=r.scroller.scrollTop;if(o&&!f){var u=n.options.resetSelectionOnContextMenu;u&&-1==n.doc.sel.contains(o)&&Gr(n,Gi)(n.doc,xi(o),j);var d=i.style.cssText,h=t.wrapper.style.cssText;t.wrapper.style.cssText="position: absolute";var p,m=t.wrapper.getBoundingClientRect();if(i.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-m.top-5)+"px; left: "+(e.clientX-m.left-5)+"px;\n z-index: 1000; background: "+(a?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);",s&&(p=window.scrollY),r.input.focus(),s&&window.scrollTo(null,p),r.input.reset(),n.somethingSelected()||(i.value=t.prevInput=" "),t.contextMenuPending=!0,r.selForContextMenu=n.doc.sel,clearTimeout(r.detectingSelectAll),a&&l>=9&&v(),C){ft(e);var g=function(){nt(window,"mouseup",g),setTimeout(y,20)};et(window,"mouseup",g)}else setTimeout(y,50)}function v(){if(null!=i.selectionStart){var e=n.somethingSelected(),o="​"+(e?i.value:"");i.value="⇚",i.value=o,t.prevInput=e?"":"​",i.selectionStart=1,i.selectionEnd=o.length,r.selForContextMenu=n.doc.sel}}function y(){if(t.contextMenuPending=!1,t.wrapper.style.cssText=h,i.style.cssText=d,a&&l<9&&r.scrollbars.setScrollTop(r.scroller.scrollTop=c),null!=i.selectionStart){(!a||a&&l<9)&&v();var e=0,o=function(){r.selForContextMenu==n.doc.sel&&0==i.selectionStart&&i.selectionEnd>0&&"​"==t.prevInput?Gr(n,no)(n):e++<10?r.detectingSelectAll=setTimeout(o,500):(r.selForContextMenu=null,r.input.reset())};r.detectingSelectAll=setTimeout(o,200)}}},Ha.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e},Ha.prototype.setUneditable=function(){},Ha.prototype.needsContentAttribute=!1,function(e){var t=e.optionHandlers;function n(n,r,i,o){e.defaults[n]=r,i&&(t[n]=o?function(e,t,n){n!=va&&i(e,t,n)}:i)}e.defineOption=n,e.Init=va,n("value","",function(e,t){return e.setValue(t)},!0),n("mode",null,function(e,t){e.doc.modeOption=t,Li(e)},!0),n("indentUnit",2,Li,!0),n("indentWithTabs",!1),n("smartIndent",!0),n("tabSize",4,function(e){Mi(e),_n(e),Jr(e)},!0),n("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(me(r,o))}r++});for(var i=n.length-1;i>=0;i--)co(e.doc,t,n[i],me(n[i].line,n[i].ch+t.length))}}),n("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=va&&e.refresh()}),n("specialCharPlaceholder",Qt,function(e){return e.refresh()},!0),n("electricChars",!0),n("inputStyle",v?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),n("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),n("rtlMoveVisually",!x),n("wholeLineUpdateBefore",!0),n("theme","default",function(e){ga(e),xa(e)},!0),n("keyMap","default",function(e,t,n){var r=Vo(t),i=n!=va&&Vo(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),n("extraKeys",null),n("configureMouse",null),n("lineWrapping",!1,ka,!0),n("gutters",[],function(e){fi(e.options),xa(e)},!0),n("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?ir(e.display)+"px":"0",e.refresh()},!0),n("coverGutterNextToScrollbar",!1,function(e){return Dr(e)},!0),n("scrollbarStyle","native",function(e){zr(e),Dr(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),n("lineNumbers",!1,function(e){fi(e.options),xa(e)},!0),n("firstLineNumber",1,xa,!0),n("lineNumberFormatter",function(e){return e},xa,!0),n("showCursorWhenSelecting",!1,cr,!0),n("resetSelectionOnContextMenu",!0),n("lineWiseCopyCut",!0),n("pasteLinesPerSelection",!0),n("readOnly",!1,function(e,t){"nocursor"==t&&(yr(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),n("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),n("dragDrop",!0,wa),n("allowDropFileTypes",null),n("cursorBlinkRate",530),n("cursorScrollMargin",0),n("cursorHeight",1,cr,!0),n("singleCursorHeightPerLine",!0,cr,!0),n("workTime",100),n("workDelay",100),n("flattenSpans",!0,Mi,!0),n("addModeClass",!1,Mi,!0),n("pollInterval",100),n("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),n("historyEventDelay",1250),n("viewportMargin",10,function(e){return e.refresh()},!0),n("maxHighlightLength",1e4,Mi,!0),n("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),n("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),n("autofocus",null),n("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0)}(Ca),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){window.focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&Gr(this,t[e])(this,n,i),rt(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](Vo(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;nn&&(La(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&Mr(this));else{var o=i.from(),a=i.to(),l=Math.max(n,o.line);n=Math.min(this.lastLine(),a.line-(a.ch?0:1))+1;for(var s=l;s0&&Vi(this.doc,r,new yi(o,c[r].to()),j)}}}),getTokenAt:function(e,t){return jt(this,e,t)},getLineTokens:function(e,t){return jt(this,me(e),t,!0)},getTokenTypeAt:function(e){e=ke(this.doc,e);var t,n=Ft(this,le(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]o&&(e=o,i=!0),r=le(this.doc,e)}else r=e;return Un(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-qe(r):0)},defaultTextHeight:function(){return tr(this.display)},defaultCharWidth:function(){return nr(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o,a,l,s=this.display,c=(e=$n(this,ke(this.doc,e))).bottom,u=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),s.sizer.appendChild(t),"over"==r)c=e.top;else if("above"==r||"near"==r){var f=Math.max(s.wrapper.clientHeight,this.doc.height),d=Math.max(s.sizer.clientWidth,s.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>f)&&e.top>t.offsetHeight?c=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=f&&(c=e.bottom),u+t.offsetWidth>d&&(u=d-t.offsetWidth)}t.style.top=c+"px",t.style.left=t.style.right="","right"==i?(u=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?u=0:"middle"==i&&(u=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=u+"px"),n&&(o=this,a={left:u,top:c,right:u+t.offsetWidth,bottom:c+t.offsetHeight},null!=(l=Sr(o,a)).scrollTop&&Nr(o,l.scrollTop),null!=l.scrollLeft&&Pr(o,l.scrollLeft))},triggerOnKeyDown:Xr(oa),triggerOnKeyPress:Xr(la),triggerOnKeyUp:aa,triggerOnMouseDown:Xr(fa),execCommand:function(e){if(Yo.hasOwnProperty(e))return Yo[e].call(null,this)},triggerElectric:Xr(function(e){Na(this,e)}),findPosH:function(e,t,n,r){var i=1;t<0&&(i=-1,t=-t);for(var o=ke(this.doc,e),a=0;a0&&l(n.charAt(r-1));)--r;for(;i.5)&&ar(this),rt(this,"refresh",this)}),swapDoc:Xr(function(e){var t=this.doc;return t.cm=null,Ni(this,e),_n(this),this.display.input.reset(),Tr(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,sn(this,"swapDoc",this,t),t}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},lt(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(Ca);var Ka="iter insert remove copy getEditor constructor".split(" ");for(var ja in Mo.prototype)Mo.prototype.hasOwnProperty(ja)&&_(Ka,ja)<0&&(Ca.prototype[ja]=function(e){return function(){return e.apply(this.doc,arguments)}}(Mo.prototype[ja]));return lt(Mo),Ca.inputStyles={textarea:Ha,contenteditable:Da},Ca.defineMode=function(e){Ca.defaults.mode||"null"==e||(Ca.defaults.mode=e),function(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),St[e]=t}.apply(this,arguments)},Ca.defineMIME=function(e,t){Lt[e]=t},Ca.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Ca.defineMIME("text/plain","null"),Ca.defineExtension=function(e,t){Ca.prototype[e]=t},Ca.defineDocExtension=function(e,t){Mo.prototype[e]=t},Ca.fromTextArea=function(e,t){if((t=t?F(t):{}).value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var n=P();t.autofocus=n==e||null!=e.getAttribute("autofocus")&&n==document.body}function r(){e.value=l.getValue()}var i;if(e.form&&(et(e.form,"submit",r),!t.leaveSubmitMethodAlone)){var o=e.form;i=o.submit;try{var a=o.submit=function(){r(),o.submit=i,o.submit(),o.submit=a}}catch(e){}}t.finishInit=function(t){t.save=r,t.getTextArea=function(){return e},t.toTextArea=function(){t.toTextArea=isNaN,r(),e.parentNode.removeChild(t.getWrapperElement()),e.style.display="",e.form&&(nt(e.form,"submit",r),"function"==typeof e.form.submit&&(e.form.submit=i))}},e.style.display="none";var l=Ca(function(t){return e.parentNode.insertBefore(t,e.nextSibling)},t);return l},function(e){e.off=nt,e.on=et,e.wheelEventPixels=mi,e.Doc=Mo,e.splitLines=xt,e.countColumn=W,e.findColumn=q,e.isWordChar=ee,e.Pass=K,e.signal=rt,e.Line=qt,e.changeEnd=wi,e.scrollbarModel=Wr,e.Pos=me,e.cmpPos=ge,e.modes=St,e.mimeModes=Lt,e.resolveMode=Mt,e.getMode=Tt,e.modeExtensions=At,e.extendMode=Ot,e.copyState=Nt,e.startState=Pt,e.innerMode=Et,e.commands=Yo,e.keyMap=Wo,e.keyName=Uo,e.isModifierKey=Ko,e.lookupKey=Ho,e.normalizeKeyMap=_o,e.StringStream=It,e.SharedTextMarker=ko,e.TextMarker=xo,e.LineWidget=vo,e.e_preventDefault=st,e.e_stopPropagation=ct,e.e_stop=ft,e.addClass=I,e.contains=E,e.rmClass=M,e.keyNames=Ro}(Ca),Ca.version="5.38.0",Ca}()},function(e,t,n){!function(e){"use strict";var t,n,r=e.Pos;function i(e,t){for(var n=function(e){var t=e.flags;return null!=t?t:(e.ignoreCase?"i":"")+(e.global?"g":"")+(e.multiline?"m":"")}(e),r=n,i=0;i>1,l=r(e.slice(0,a)).length;if(l==n)return a;l>n?o=a:i=a+1}}function s(e,s,c,u){var f;this.atOccurrence=!1,this.doc=e,c=c?e.clipPos(c):r(0,0),this.pos={from:c,to:c},"object"==typeof u?f=u.caseFold:(f=u,u=null),"string"==typeof s?(null==f&&(f=!1),this.matches=function(i,o){return(i?function(e,i,o,a){if(!i.length)return null;var s=a?t:n,c=s(i).split(/\r|\n\r?/);e:for(var u=o.line,f=o.ch,d=e.firstLine()-1+c.length;u>=d;u--,f=-1){var h=e.getLine(u);f>-1&&(h=h.slice(0,f));var p=s(h);if(1==c.length){var m=p.lastIndexOf(c[0]);if(-1==m)continue e;return{from:r(u,l(h,p,m,s)),to:r(u,l(h,p,m+c[0].length,s))}}var g=c[c.length-1];if(p.slice(0,g.length)==g){for(var v=1,o=u-c.length+1;v=s;o--,l=-1){var c=e.getLine(o);l>-1&&(c=c.slice(0,l));var u=a(c,t);if(u)return{from:r(o,u.index),to:r(o,u.index+u[0].length),match:u}}}:o)(e,s,n)}:this.matches=function(t,n){return(t?function(e,t,n){t=i(t,"gm");for(var o,l=1,s=n.line,c=e.firstLine();s>=c;){for(var u=0;uc);u++){var f=e.getLine(s++);a=null==a?f:a+"\n"+f}l*=2,t.lastIndex=n.ch;var d=t.exec(a);if(d){var h=a.slice(0,d.index).split("\n"),p=d[0].split("\n"),m=n.line+h.length-1,g=h[h.length-1].length;return{from:r(m,g),to:r(m+p.length-1,1==p.length?g+p[0].length:p[p.length-1].length),match:d}}}})(e,s,n)})}String.prototype.normalize?(t=function(e){return e.normalize("NFD").toLowerCase()},n=function(e){return e.normalize("NFD")}):(t=function(e){return e.toLowerCase()},n=function(e){return e}),s.prototype={findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(t){for(var n=this.matches(t,this.doc.clipPos(t?this.pos.from:this.pos.to));n&&0==e.cmpPos(n.from,n.to);)t?n.from.ch?n.from=r(n.from.line,n.from.ch-1):n=n.from.line==this.doc.firstLine()?null:this.matches(t,this.doc.clipPos(r(n.from.line-1))):n.to.ch0);)r.push({anchor:i.from(),head:i.to()});r.length&&this.setSelections(r,0)})}(n(0))},function(e,t,n){!function(e){"use strict";var t={autoSelfClosers:{area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,frame:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0,menuitem:!0},implicitlyClosed:{dd:!0,li:!0,optgroup:!0,option:!0,p:!0,rp:!0,rt:!0,tbody:!0,td:!0,tfoot:!0,th:!0,tr:!0},contextGrabbers:{dd:{dd:!0,dt:!0},dt:{dd:!0,dt:!0},li:{li:!0},option:{option:!0,optgroup:!0},optgroup:{optgroup:!0},p:{address:!0,article:!0,aside:!0,blockquote:!0,dir:!0,div:!0,dl:!0,fieldset:!0,footer:!0,form:!0,h1:!0,h2:!0,h3:!0,h4:!0,h5:!0,h6:!0,header:!0,hgroup:!0,hr:!0,menu:!0,nav:!0,ol:!0,p:!0,pre:!0,section:!0,table:!0,ul:!0},rp:{rp:!0,rt:!0},rt:{rp:!0,rt:!0},tbody:{tbody:!0,tfoot:!0},td:{td:!0,th:!0},tfoot:{tbody:!0},th:{td:!0,th:!0},thead:{tbody:!0,tfoot:!0},tr:{tr:!0}},doNotIndent:{pre:!0},allowUnquoted:!0,allowMissing:!0,caseFold:!0},n={autoSelfClosers:{},implicitlyClosed:{},contextGrabbers:{},doNotIndent:{},allowUnquoted:!1,allowMissing:!1,allowMissingTagName:!1,caseFold:!1};e.defineMode("xml",function(r,i){var o,a,l=r.indentUnit,s={},c=i.htmlMode?t:n;for(var u in c)s[u]=c[u];for(var u in i)s[u]=i[u];function f(e,t){function n(n){return t.tokenize=n,n(e,t)}var r=e.next();return"<"==r?e.eat("!")?e.eat("[")?e.match("CDATA[")?n(h("atom","]]>")):null:e.match("--")?n(h("comment","--\x3e")):e.match("DOCTYPE",!0,!0)?(e.eatWhile(/[\w\._\-]/),n(function e(t){return function(n,r){for(var i;null!=(i=n.next());){if("<"==i)return r.tokenize=e(t+1),r.tokenize(n,r);if(">"==i){if(1==t){r.tokenize=f;break}return r.tokenize=e(t-1),r.tokenize(n,r)}}return"meta"}}(1))):null:e.eat("?")?(e.eatWhile(/[\w\._\-]/),t.tokenize=h("meta","?>"),"meta"):(o=e.eat("/")?"closeTag":"openTag",t.tokenize=d,"tag bracket"):"&"==r?(e.eat("#")?e.eat("x")?e.eatWhile(/[a-fA-F\d]/)&&e.eat(";"):e.eatWhile(/[\d]/)&&e.eat(";"):e.eatWhile(/[\w\.\-:]/)&&e.eat(";"))?"atom":"error":(e.eatWhile(/[^&<]/),null)}function d(e,t){var n,r,i=e.next();if(">"==i||"/"==i&&e.eat(">"))return t.tokenize=f,o=">"==i?"endTag":"selfcloseTag","tag bracket";if("="==i)return o="equals",null;if("<"==i){t.tokenize=f,t.state=g,t.tagName=t.tagStart=null;var a=t.tokenize(e,t);return a?a+" tag error":"tag error"}return/[\'\"]/.test(i)?(t.tokenize=(n=i,(r=function(e,t){for(;!e.eol();)if(e.next()==n){t.tokenize=d;break}return"string"}).isInAttribute=!0,r),t.stringStartCol=e.column(),t.tokenize(e,t)):(e.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/),"word")}function h(e,t){return function(n,r){for(;!n.eol();){if(n.match(t)){r.tokenize=f;break}n.next()}return e}}function p(e){e.context&&(e.context=e.context.prev)}function m(e,t){for(var n;;){if(!e.context)return;if(n=e.context.tagName,!s.contextGrabbers.hasOwnProperty(n)||!s.contextGrabbers[n].hasOwnProperty(t))return;p(e)}}function g(e,t,n){return"openTag"==e?(n.tagStart=t.column(),v):"closeTag"==e?y:g}function v(e,t,n){return"word"==e?(n.tagName=t.current(),a="tag",w):s.allowMissingTagName&&"endTag"==e?(a="tag bracket",w(e,0,n)):(a="error",v)}function y(e,t,n){if("word"==e){var r=t.current();return n.context&&n.context.tagName!=r&&s.implicitlyClosed.hasOwnProperty(n.context.tagName)&&p(n),n.context&&n.context.tagName==r||!1===s.matchClosing?(a="tag",b):(a="tag error",x)}return s.allowMissingTagName&&"endTag"==e?(a="tag bracket",b(e,0,n)):(a="error",x)}function b(e,t,n){return"endTag"!=e?(a="error",b):(p(n),g)}function x(e,t,n){return a="error",b(e,0,n)}function w(e,t,n){if("word"==e)return a="attribute",k;if("endTag"==e||"selfcloseTag"==e){var r=n.tagName,i=n.tagStart;return n.tagName=n.tagStart=null,"selfcloseTag"==e||s.autoSelfClosers.hasOwnProperty(r)?m(n,r):(m(n,r),n.context=new function(e,t,n){this.prev=e.context,this.tagName=t,this.indent=e.indented,this.startOfLine=n,(s.doNotIndent.hasOwnProperty(t)||e.context&&e.context.noIndent)&&(this.noIndent=!0)}(n,r,i==n.indented)),g}return a="error",w}function k(e,t,n){return"equals"==e?C:(s.allowMissing||(a="error"),w(e,0,n))}function C(e,t,n){return"string"==e?S:"word"==e&&s.allowUnquoted?(a="string",w):(a="error",w(e,0,n))}function S(e,t,n){return"string"==e?S:w(e,0,n)}return f.isInText=!0,{startState:function(e){var t={tokenize:f,state:g,indented:e||0,tagName:null,tagStart:null,context:null};return null!=e&&(t.baseIndent=e),t},token:function(e,t){if(!t.tagName&&e.sol()&&(t.indented=e.indentation()),e.eatSpace())return null;o=null;var n=t.tokenize(e,t);return(n||o)&&"comment"!=n&&(a=null,t.state=t.state(o||n,e,t),a&&(n="error"==a?n+" error":a)),n},indent:function(t,n,r){var i=t.context;if(t.tokenize.isInAttribute)return t.tagStart==t.indented?t.stringStartCol+1:t.indented+l;if(i&&i.noIndent)return e.Pass;if(t.tokenize!=d&&t.tokenize!=f)return r?r.match(/^(\s*)/)[0].length:0;if(t.tagName)return!1!==s.multilineTagIndentPastTag?t.tagStart+t.tagName.length+2:t.tagStart+l*(s.multilineTagIndentFactor||1);if(s.alignCDATA&&/$/,blockCommentStart:"\x3c!--",blockCommentEnd:"--\x3e",configuration:s.htmlMode?"html":"xml",helperType:s.htmlMode?"html":"xml",skipAttribute:function(e){e.state==C&&(e.state=w)}}}),e.defineMIME("text/xml","xml"),e.defineMIME("application/xml","xml"),e.mimeModes.hasOwnProperty("text/html")||e.defineMIME("text/html",{name:"xml",htmlMode:!0})}(n(0))},function(e,t,n){!function(e){"use strict";e.defineMode("javascript",function(t,n){var r,i,o=t.indentUnit,a=n.statementIndent,l=n.jsonld,s=n.json||l,c=n.typescript,u=n.wordCharacters||/[\w$\xa1-\uffff]/,f=function(){function e(e){return{type:e,style:"keyword"}}var t=e("keyword a"),n=e("keyword b"),r=e("keyword c"),i=e("keyword d"),o=e("operator"),a={type:"atom",style:"atom"};return{if:e("if"),while:t,with:t,else:n,do:n,try:n,finally:n,return:i,break:i,continue:i,new:e("new"),delete:r,void:r,throw:r,debugger:e("debugger"),var:e("var"),const:e("var"),let:e("var"),function:e("function"),catch:e("catch"),for:e("for"),switch:e("switch"),case:e("case"),default:e("default"),in:o,typeof:o,instanceof:o,true:a,false:a,null:a,undefined:a,NaN:a,Infinity:a,this:e("this"),class:e("class"),super:e("atom"),yield:r,export:e("export"),import:e("import"),extends:r,await:r}}(),d=/[+\-*&%=<>!?|~^@]/,h=/^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;function p(e,t,n){return r=e,i=n,t}function m(e,t){var n,r=e.next();if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){var r,i=!1;if(l&&"@"==e.peek()&&e.match(h))return t.tokenize=m,p("jsonld-keyword","meta");for(;null!=(r=e.next())&&(r!=n||i);)i=!i&&"\\"==r;return i||(t.tokenize=m),p("string","string")}),t.tokenize(e,t);if("."==r&&e.match(/^\d+(?:[eE][+\-]?\d+)?/))return p("number","number");if("."==r&&e.match(".."))return p("spread","meta");if(/[\[\]{}\(\),;\:\.]/.test(r))return p(r);if("="==r&&e.eat(">"))return p("=>","operator");if("0"==r&&e.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i))return p("number","number");if(/\d/.test(r))return e.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/),p("number","number");if("/"==r)return e.eat("*")?(t.tokenize=g,g(e,t)):e.eat("/")?(e.skipToEnd(),p("comment","comment")):qe(e,t,1)?(function(e){for(var t,n=!1,r=!1;null!=(t=e.next());){if(!n){if("/"==t&&!r)return;"["==t?r=!0:r&&"]"==t&&(r=!1)}n=!n&&"\\"==t}}(e),e.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/),p("regexp","string-2")):(e.eat("="),p("operator","operator",e.current()));if("`"==r)return t.tokenize=v,v(e,t);if("#"==r)return e.skipToEnd(),p("error","error");if(d.test(r))return">"==r&&t.lexical&&">"==t.lexical.type||(e.eat("=")?"!"!=r&&"="!=r||e.eat("="):/[<>*+\-]/.test(r)&&(e.eat(r),">"==r&&e.eat(r))),p("operator","operator",e.current());if(u.test(r)){e.eatWhile(u);var i=e.current();if("."!=t.lastType){if(f.propertyIsEnumerable(i)){var o=f[i];return p(o.type,o.style,i)}if("async"==i&&e.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/,!1))return p("async","keyword",i)}return p("variable","variable",i)}}function g(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=m;break}r="*"==n}return p("comment","comment")}function v(e,t){for(var n,r=!1;null!=(n=e.next());){if(!r&&("`"==n||"$"==n&&e.eat("{"))){t.tokenize=m;break}r=!r&&"\\"==n}return p("quasi","string-2",e.current())}var y="([{}])";function b(e,t){t.fatArrowAt&&(t.fatArrowAt=null);var n=e.string.indexOf("=>",e.start);if(!(n<0)){if(c){var r=/:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(e.string.slice(e.start,n));r&&(n=r.index)}for(var i=0,o=!1,a=n-1;a>=0;--a){var l=e.string.charAt(a),s=y.indexOf(l);if(s>=0&&s<3){if(!i){++a;break}if(0==--i){"("==l&&(o=!0);break}}else if(s>=3&&s<6)++i;else if(u.test(l))o=!0;else{if(/["'\/]/.test(l))return;if(o&&!i){++a;break}}}o&&!i&&(t.fatArrowAt=a)}}var x={atom:!0,number:!0,variable:!0,string:!0,regexp:!0,this:!0,"jsonld-keyword":!0};function w(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.prev=i,this.info=o,null!=r&&(this.align=r)}function k(e,t){for(var n=e.localVars;n;n=n.next)if(n.name==t)return!0;for(var r=e.context;r;r=r.prev)for(var n=r.vars;n;n=n.next)if(n.name==t)return!0}var C={state:null,column:null,marked:null,cc:null};function S(){for(var e=arguments.length-1;e>=0;e--)C.cc.push(arguments[e])}function L(){return S.apply(null,arguments),!0}function M(e,t){for(var n=t;n;n=n.next)if(n.name==e)return!0;return!1}function T(e){var t=C.state;if(C.marked="def",t.context)if("var"==t.lexical.info&&t.context&&t.context.block){var r=function e(t,n){if(n){if(n.block){var r=e(t,n.prev);return r?r==n.prev?n:new O(r,n.vars,!0):null}return M(t,n.vars)?n:new O(n.prev,new N(t,n.vars),!1)}return null}(e,t.context);if(null!=r)return void(t.context=r)}else if(!M(e,t.localVars))return void(t.localVars=new N(e,t.localVars));n.globalVars&&!M(e,t.globalVars)&&(t.globalVars=new N(e,t.globalVars))}function A(e){return"public"==e||"private"==e||"protected"==e||"abstract"==e||"readonly"==e}function O(e,t,n){this.prev=e,this.vars=t,this.block=n}function N(e,t){this.name=e,this.next=t}var E=new N("this",new N("arguments",null));function P(){C.state.context=new O(C.state.context,C.state.localVars,!1),C.state.localVars=E}function I(){C.state.context=new O(C.state.context,C.state.localVars,!0),C.state.localVars=null}function R(){C.state.localVars=C.state.context.vars,C.state.context=C.state.context.prev}function B(e,t){var n=function(){var n=C.state,r=n.indented;if("stat"==n.lexical.type)r=n.lexical.indented;else for(var i=n.lexical;i&&")"==i.type&&i.align;i=i.prev)r=i.indented;n.lexical=new w(r,C.stream.column(),e,null,n.lexical,t)};return n.lex=!0,n}function D(){var e=C.state;e.lexical.prev&&(")"==e.lexical.type&&(e.indented=e.lexical.indented),e.lexical=e.lexical.prev)}function F(e){return function t(n){return n==e?L():";"==e?S():L(t)}}function W(e,t){return"var"==e?L(B("vardef",t),ye,F(";"),D):"keyword a"==e?L(B("form"),K,W,D):"keyword b"==e?L(B("form"),W,D):"keyword d"==e?C.stream.match(/^\s*$/,!1)?L():L(B("stat"),U,F(";"),D):"debugger"==e?L(F(";")):"{"==e?L(B("}"),I,ae,D,R):";"==e?L():"if"==e?("else"==C.state.lexical.info&&C.state.cc[C.state.cc.length-1]==D&&C.state.cc.pop()(),L(B("form"),K,W,D,Ce)):"function"==e?L(Oe):"for"==e?L(B("form"),Se,W,D):"class"==e||c&&"interface"==t?(C.marked="keyword",L(B("form"),Pe,D)):"variable"==e?c&&"declare"==t?(C.marked="keyword",L(W)):c&&("module"==t||"enum"==t||"type"==t)&&C.stream.match(/^\s*\w/,!1)?(C.marked="keyword","enum"==t?L(Ue):"type"==t?L(ue,F("operator"),ue,F(";")):L(B("form"),be,F("{"),B("}"),ae,D,D)):c&&"namespace"==t?(C.marked="keyword",L(B("form"),_,ae,D)):c&&"abstract"==t?(C.marked="keyword",L(W)):L(B("stat"),Z):"switch"==e?L(B("form"),K,F("{"),B("}","switch"),I,ae,D,D,R):"case"==e?L(_,F(":")):"default"==e?L(F(":")):"catch"==e?L(B("form"),P,z,W,D,R):"export"==e?L(B("stat"),De,D):"import"==e?L(B("stat"),We,D):"async"==e?L(W):"@"==t?L(_,W):S(B("stat"),_,F(";"),D)}function z(e){if("("==e)return L(Ne,F(")"))}function _(e,t){return j(e,t,!1)}function H(e,t){return j(e,t,!0)}function K(e){return"("!=e?S():L(B(")"),_,F(")"),D)}function j(e,t,n){if(C.state.fatArrowAt==C.stream.start){var r=n?Y:X;if("("==e)return L(P,B(")"),ie(Ne,")"),D,F("=>"),r,R);if("variable"==e)return S(P,be,F("=>"),r,R)}var i=n?q:V;return x.hasOwnProperty(e)?L(i):"function"==e?L(Oe,i):"class"==e||c&&"interface"==t?(C.marked="keyword",L(B("form"),Ee,D)):"keyword c"==e||"async"==e?L(n?H:_):"("==e?L(B(")"),U,F(")"),D,i):"operator"==e||"spread"==e?L(n?H:_):"["==e?L(B("]"),je,D,i):"{"==e?oe(te,"}",null,i):"quasi"==e?S($,i):"new"==e?L(function(e){return function(t){return"."==t?L(e?Q:J):"variable"==t&&c?L(me,e?q:V):S(e?H:_)}}(n)):"import"==e?L(_):L()}function U(e){return e.match(/[;\}\)\],]/)?S():S(_)}function V(e,t){return","==e?L(_):q(e,t,!1)}function q(e,t,n){var r=0==n?V:q,i=0==n?_:H;return"=>"==e?L(P,n?Y:X,R):"operator"==e?/\+\+|--/.test(t)||c&&"!"==t?L(r):c&&"<"==t&&C.stream.match(/^([^>]|<.*?>)*>\s*\(/,!1)?L(B(">"),ie(ue,">"),D,r):"?"==t?L(_,F(":"),i):L(i):"quasi"==e?S($,r):";"!=e?"("==e?oe(H,")","call",r):"."==e?L(ee,r):"["==e?L(B("]"),U,F("]"),D,r):c&&"as"==t?(C.marked="keyword",L(ue,r)):"regexp"==e?(C.state.lastType=C.marked="operator",C.stream.backUp(C.stream.pos-C.stream.start-1),L(i)):void 0:void 0}function $(e,t){return"quasi"!=e?S():"${"!=t.slice(t.length-2)?L($):L(_,G)}function G(e){if("}"==e)return C.marked="string-2",C.state.tokenize=v,L($)}function X(e){return b(C.stream,C.state),S("{"==e?W:_)}function Y(e){return b(C.stream,C.state),S("{"==e?W:H)}function J(e,t){if("target"==t)return C.marked="keyword",L(V)}function Q(e,t){if("target"==t)return C.marked="keyword",L(q)}function Z(e){return":"==e?L(D,W):S(V,F(";"),D)}function ee(e){if("variable"==e)return C.marked="property",L()}function te(e,t){if("async"==e)return C.marked="property",L(te);if("variable"==e||"keyword"==C.style){return C.marked="property","get"==t||"set"==t?L(ne):(c&&C.state.fatArrowAt==C.stream.start&&(n=C.stream.match(/^\s*:\s*/,!1))&&(C.state.fatArrowAt=C.stream.pos+n[0].length),L(re));var n}else{if("number"==e||"string"==e)return C.marked=l?"property":C.style+" property",L(re);if("jsonld-keyword"==e)return L(re);if(c&&A(t))return C.marked="keyword",L(te);if("["==e)return L(_,le,F("]"),re);if("spread"==e)return L(H,re);if("*"==t)return C.marked="keyword",L(te);if(":"==e)return S(re)}}function ne(e){return"variable"!=e?S(re):(C.marked="property",L(Oe))}function re(e){return":"==e?L(H):"("==e?S(Oe):void 0}function ie(e,t,n){function r(i,o){if(n?n.indexOf(i)>-1:","==i){var a=C.state.lexical;return"call"==a.info&&(a.pos=(a.pos||0)+1),L(function(n,r){return n==t||r==t?S():S(e)},r)}return i==t||o==t?L():L(F(t))}return function(n,i){return n==t||i==t?L():S(e,r)}}function oe(e,t,n){for(var r=3;r"),ue):void 0}function fe(e){if("=>"==e)return L(ue)}function de(e,t){return"variable"==e||"keyword"==C.style?(C.marked="property",L(de)):"?"==t?L(de):":"==e?L(ue):"["==e?L(_,le,F("]"),de):void 0}function he(e,t){return"variable"==e&&C.stream.match(/^\s*[?:]/,!1)||"?"==t?L(he):":"==e?L(ue):S(ue)}function pe(e,t){return"<"==t?L(B(">"),ie(ue,">"),D,pe):"|"==t||"."==e||"&"==t?L(ue):"["==e?L(F("]"),pe):"extends"==t||"implements"==t?(C.marked="keyword",L(ue)):void 0}function me(e,t){if("<"==t)return L(B(">"),ie(ue,">"),D,pe)}function ge(){return S(ue,ve)}function ve(e,t){if("="==t)return L(ue)}function ye(e,t){return"enum"==t?(C.marked="keyword",L(Ue)):S(be,le,we,ke)}function be(e,t){return c&&A(t)?(C.marked="keyword",L(be)):"variable"==e?(T(t),L()):"spread"==e?L(be):"["==e?oe(be,"]"):"{"==e?oe(xe,"}"):void 0}function xe(e,t){return"variable"!=e||C.stream.match(/^\s*:/,!1)?("variable"==e&&(C.marked="property"),"spread"==e?L(be):"}"==e?S():L(F(":"),be,we)):(T(t),L(we))}function we(e,t){if("="==t)return L(H)}function ke(e){if(","==e)return L(ye)}function Ce(e,t){if("keyword b"==e&&"else"==t)return L(B("form","else"),W,D)}function Se(e,t){return"await"==t?L(Se):"("==e?L(B(")"),Le,F(")"),D):void 0}function Le(e){return"var"==e?L(ye,F(";"),Te):";"==e?L(Te):"variable"==e?L(Me):S(_,F(";"),Te)}function Me(e,t){return"in"==t||"of"==t?(C.marked="keyword",L(_)):L(V,Te)}function Te(e,t){return";"==e?L(Ae):"in"==t||"of"==t?(C.marked="keyword",L(_)):S(_,F(";"),Ae)}function Ae(e){")"!=e&&L(_)}function Oe(e,t){return"*"==t?(C.marked="keyword",L(Oe)):"variable"==e?(T(t),L(Oe)):"("==e?L(P,B(")"),ie(Ne,")"),D,se,W,R):c&&"<"==t?L(B(">"),ie(ge,">"),D,Oe):void 0}function Ne(e,t){return"@"==t&&L(_,Ne),"spread"==e?L(Ne):c&&A(t)?(C.marked="keyword",L(Ne)):S(be,le,we)}function Ee(e,t){return"variable"==e?Pe(e,t):Ie(e,t)}function Pe(e,t){if("variable"==e)return T(t),L(Ie)}function Ie(e,t){return"<"==t?L(B(">"),ie(ge,">"),D,Ie):"extends"==t||"implements"==t||c&&","==e?("implements"==t&&(C.marked="keyword"),L(c?ue:_,Ie)):"{"==e?L(B("}"),Re,D):void 0}function Re(e,t){return"async"==e||"variable"==e&&("static"==t||"get"==t||"set"==t||c&&A(t))&&C.stream.match(/^\s+[\w$\xa1-\uffff]/,!1)?(C.marked="keyword",L(Re)):"variable"==e||"keyword"==C.style?(C.marked="property",L(c?Be:Oe,Re)):"["==e?L(_,le,F("]"),c?Be:Oe,Re):"*"==t?(C.marked="keyword",L(Re)):";"==e?L(Re):"}"==e?L():"@"==t?L(_,Re):void 0}function Be(e,t){return"?"==t?L(Be):":"==e?L(ue,we):"="==t?L(H):S(Oe)}function De(e,t){return"*"==t?(C.marked="keyword",L(Ke,F(";"))):"default"==t?(C.marked="keyword",L(_,F(";"))):"{"==e?L(ie(Fe,"}"),Ke,F(";")):S(W)}function Fe(e,t){return"as"==t?(C.marked="keyword",L(F("variable"))):"variable"==e?S(H,Fe):void 0}function We(e){return"string"==e?L():"("==e?S(_):S(ze,_e,Ke)}function ze(e,t){return"{"==e?oe(ze,"}"):("variable"==e&&T(t),"*"==t&&(C.marked="keyword"),L(He))}function _e(e){if(","==e)return L(ze,_e)}function He(e,t){if("as"==t)return C.marked="keyword",L(ze)}function Ke(e,t){if("from"==t)return C.marked="keyword",L(_)}function je(e){return"]"==e?L():S(ie(H,"]"))}function Ue(){return S(B("form"),be,F("{"),B("}"),ie(Ve,"}"),D,D)}function Ve(){return S(be,we)}function qe(e,t,n){return t.tokenize==m&&/^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(t.lastType)||"quasi"==t.lastType&&/\{\s*$/.test(e.string.slice(0,e.pos-(n||0)))}return R.lex=!0,D.lex=!0,{startState:function(e){var t={tokenize:m,lastType:"sof",cc:[],lexical:new w((e||0)-o,0,"block",!1),localVars:n.localVars,context:n.localVars&&new O(null,null,!1),indented:e||0};return n.globalVars&&"object"==typeof n.globalVars&&(t.globalVars=n.globalVars),t},token:function(e,t){if(e.sol()&&(t.lexical.hasOwnProperty("align")||(t.lexical.align=!1),t.indented=e.indentation(),b(e,t)),t.tokenize!=g&&e.eatSpace())return null;var n=t.tokenize(e,t);return"comment"==r?n:(t.lastType="operator"!=r||"++"!=i&&"--"!=i?r:"incdec",function(e,t,n,r,i){var o=e.cc;for(C.state=e,C.stream=i,C.marked=null,C.cc=o,C.style=t,e.lexical.hasOwnProperty("align")||(e.lexical.align=!0);;){var a=o.length?o.pop():s?_:W;if(a(n,r)){for(;o.length&&o[o.length-1].lex;)o.pop()();return C.marked?C.marked:"variable"==n&&k(e,r)?"variable-2":t}}}(t,n,r,i,e))},indent:function(t,r){if(t.tokenize==g)return e.Pass;if(t.tokenize!=m)return 0;var i,l=r&&r.charAt(0),s=t.lexical;if(!/^\s*else\b/.test(r))for(var c=t.cc.length-1;c>=0;--c){var u=t.cc[c];if(u==D)s=s.prev;else if(u!=Ce)break}for(;("stat"==s.type||"form"==s.type)&&("}"==l||(i=t.cc[t.cc.length-1])&&(i==V||i==q)&&!/^[,\.=+\-*:?[\(]/.test(r));)s=s.prev;a&&")"==s.type&&"stat"==s.prev.type&&(s=s.prev);var f=s.type,h=l==f;return"vardef"==f?s.indented+("operator"==t.lastType||","==t.lastType?s.info.length+1:0):"form"==f&&"{"==l?s.indented:"form"==f?s.indented+o:"stat"==f?s.indented+(function(e,t){return"operator"==e.lastType||","==e.lastType||d.test(t.charAt(0))||/[,.]/.test(t.charAt(0))}(t,r)?a||o:0):"switch"!=s.info||h||0==n.doubleIndentSwitch?s.align?s.column+(h?0:1):s.indented+(h?0:o):s.indented+(/^(?:case|default)\b/.test(r)?o:2*o)},electricInput:/^\s*(?:case .*?:|default:|\{|\})$/,blockCommentStart:s?null:"/*",blockCommentEnd:s?null:"*/",blockCommentContinue:s?null:" * ",lineComment:s?null:"//",fold:"brace",closeBrackets:"()[]{}''\"\"``",helperType:s?"json":"javascript",jsonldMode:l,jsonMode:s,expressionAllowed:qe,skipExpression:function(e){var t=e.cc[e.cc.length-1];t!=_&&t!=H||e.cc.pop()}}}),e.registerHelper("wordChars","javascript",/[\w$]/),e.defineMIME("text/javascript","javascript"),e.defineMIME("text/ecmascript","javascript"),e.defineMIME("application/javascript","javascript"),e.defineMIME("application/x-javascript","javascript"),e.defineMIME("application/ecmascript","javascript"),e.defineMIME("application/json",{name:"javascript",json:!0}),e.defineMIME("application/x-json",{name:"javascript",json:!0}),e.defineMIME("application/ld+json",{name:"javascript",jsonld:!0}),e.defineMIME("text/typescript",{name:"javascript",typescript:!0}),e.defineMIME("application/typescript",{name:"javascript",typescript:!0})}(n(0))},function(e,t,n){!function(e){var t=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),n=e.Pos,r={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<"};function i(e,t,i){var a=e.getLineHandle(t.line),l=t.ch-1,s=i&&i.afterCursor;null==s&&(s=/(^| )cm-fat-cursor($| )/.test(e.getWrapperElement().className));var c=!s&&l>=0&&r[a.text.charAt(l)]||r[a.text.charAt(++l)];if(!c)return null;var u=">"==c.charAt(1)?1:-1;if(i&&i.strict&&u>0!=(l==t.ch))return null;var f=e.getTokenTypeAt(n(t.line,l+1)),d=o(e,n(t.line,l+(u>0?1:0)),u,f||null,i);return null==d?null:{from:n(t.line,l),to:d&&d.pos,match:d&&d.ch==c.charAt(0),forward:u>0}}function o(e,t,i,o,a){for(var l=a&&a.maxScanLineLength||1e4,s=a&&a.maxScanLines||1e3,c=[],u=a&&a.bracketRegex?a.bracketRegex:/[(){}[\]]/,f=i>0?Math.min(t.line+s,e.lastLine()+1):Math.max(e.firstLine()-1,t.line-s),d=t.line;d!=f;d+=i){var h=e.getLine(d);if(h){var p=i>0?0:h.length-1,m=i>0?h.length:-1;if(!(h.length>l))for(d==t.line&&(p=t.ch-(i<0?1:0));p!=m;p+=i){var g=h.charAt(p);if(u.test(g)&&(void 0===o||e.getTokenTypeAt(n(d,p+1))==o)){var v=r[g];if(">"==v.charAt(1)==i>0)c.push(g);else{if(!c.length)return{pos:n(d,p),ch:g};c.pop()}}}}}return d-i!=(i>0?e.lastLine():e.firstLine())&&null}function a(e,r,o){for(var a=e.state.matchBrackets.maxHighlightLineLength||1e3,l=[],s=e.listSelections(),c=0;ct.firstLine();)n=e.Pos(n.line-1,0),c=s(!1);if(c&&!c.cleared&&"unfold"!==o){var u=function(e,t){var n=r(e,t,"widget");if("string"==typeof n){var i=document.createTextNode(n);(n=document.createElement("span")).appendChild(i),n.className="CodeMirror-foldmarker"}else n&&(n=n.cloneNode(!0));return n}(t,i);e.on(u,"mousedown",function(t){f.clear(),e.e_preventDefault(t)});var f=t.markText(c.from,c.to,{replacedWith:u,clearOnEnter:r(t,i,"clearOnEnter"),__isFold:!0});f.on("clear",function(n,r){e.signal(t,"unfold",t,n,r)}),e.signal(t,"fold",t,c.from,c.to)}}e.newFoldFunction=function(e,n){return function(r,i){t(r,i,{rangeFinder:e,widget:n})}},e.defineExtension("foldCode",function(e,n,r){t(this,e,n,r)}),e.defineExtension("isFolded",function(e){for(var t=this.findMarksAt(e),n=0;n0;i--)n.context=n.context.prev;return T(e,t,n)}function O(e){var t=e.current().toLowerCase();o=v.hasOwnProperty(t)?"atom":g.hasOwnProperty(t)?"keyword":"variable"}var N={top:function(e,t,n){if("{"==e)return L(n,t,"block");if("}"==e&&n.context.prev)return M(n);if(x&&/@component/i.test(e))return L(n,t,"atComponentBlock");if(/^@(-moz-)?document$/i.test(e))return L(n,t,"documentTypes");if(/^@(media|supports|(-moz-)?document|import)$/i.test(e))return L(n,t,"atBlock");if(/^@(font-face|counter-style)/i.test(e))return n.stateArg=e,"restricted_atBlock_before";if(/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(e))return"keyframes";if(e&&"@"==e.charAt(0))return L(n,t,"at");if("hash"==e)o="builtin";else if("word"==e)o="tag";else{if("variable-definition"==e)return"maybeprop";if("interpolation"==e)return L(n,t,"interpolation");if(":"==e)return"pseudo";if(y&&"("==e)return L(n,t,"parens")}return n.context.type},block:function(e,t,n){if("word"==e){var r=t.current().toLowerCase();return d.hasOwnProperty(r)?(o="property","maybeprop"):h.hasOwnProperty(r)?(o="string-2","maybeprop"):y?(o=t.match(/^\s*:(?:\s|$)/,!1)?"property":"tag","block"):(o+=" error","maybeprop")}return"meta"==e?"block":y||"hash"!=e&&"qualifier"!=e?N.top(e,t,n):(o="error","block")},maybeprop:function(e,t,n){return":"==e?L(n,t,"prop"):T(e,t,n)},prop:function(e,t,n){if(";"==e)return M(n);if("{"==e&&y)return L(n,t,"propBlock");if("}"==e||"{"==e)return A(e,t,n);if("("==e)return L(n,t,"parens");if("hash"!=e||/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(t.current())){if("word"==e)O(t);else if("interpolation"==e)return L(n,t,"interpolation")}else o+=" error";return"prop"},propBlock:function(e,t,n){return"}"==e?M(n):"word"==e?(o="property","maybeprop"):n.context.type},parens:function(e,t,n){return"{"==e||"}"==e?A(e,t,n):")"==e?M(n):"("==e?L(n,t,"parens"):"interpolation"==e?L(n,t,"interpolation"):("word"==e&&O(t),"parens")},pseudo:function(e,t,n){return"meta"==e?"pseudo":"word"==e?(o="variable-3",n.context.type):T(e,t,n)},documentTypes:function(e,t,n){return"word"==e&&s.hasOwnProperty(t.current())?(o="tag",n.context.type):N.atBlock(e,t,n)},atBlock:function(e,t,n){if("("==e)return L(n,t,"atBlock_parens");if("}"==e||";"==e)return A(e,t,n);if("{"==e)return M(n)&&L(n,t,y?"block":"top");if("interpolation"==e)return L(n,t,"interpolation");if("word"==e){var r=t.current().toLowerCase();o="only"==r||"not"==r||"and"==r||"or"==r?"keyword":c.hasOwnProperty(r)?"attribute":u.hasOwnProperty(r)?"property":f.hasOwnProperty(r)?"keyword":d.hasOwnProperty(r)?"property":h.hasOwnProperty(r)?"string-2":v.hasOwnProperty(r)?"atom":g.hasOwnProperty(r)?"keyword":"error"}return n.context.type},atComponentBlock:function(e,t,n){return"}"==e?A(e,t,n):"{"==e?M(n)&&L(n,t,y?"block":"top",!1):("word"==e&&(o="error"),n.context.type)},atBlock_parens:function(e,t,n){return")"==e?M(n):"{"==e||"}"==e?A(e,t,n,2):N.atBlock(e,t,n)},restricted_atBlock_before:function(e,t,n){return"{"==e?L(n,t,"restricted_atBlock"):"word"==e&&"@counter-style"==n.stateArg?(o="variable","restricted_atBlock_before"):T(e,t,n)},restricted_atBlock:function(e,t,n){return"}"==e?(n.stateArg=null,M(n)):"word"==e?(o="@font-face"==n.stateArg&&!p.hasOwnProperty(t.current().toLowerCase())||"@counter-style"==n.stateArg&&!m.hasOwnProperty(t.current().toLowerCase())?"error":"property","maybeprop"):"restricted_atBlock"},keyframes:function(e,t,n){return"word"==e?(o="variable","keyframes"):"{"==e?L(n,t,"top"):T(e,t,n)},at:function(e,t,n){return";"==e?M(n):"{"==e||"}"==e?A(e,t,n):("word"==e?o="tag":"hash"==e&&(o="builtin"),"at")},interpolation:function(e,t,n){return"}"==e?M(n):"{"==e||";"==e?A(e,t,n):("word"==e?o="variable":"variable"!=e&&"("!=e&&")"!=e&&(o="error"),"interpolation")}};return{startState:function(e){return{tokenize:null,state:r?"block":"top",stateArg:null,context:new S(r?"block":"top",e||0,null)}},token:function(e,t){if(!t.tokenize&&e.eatSpace())return null;var n=(t.tokenize||function(e,t){var n=e.next();if(l[n]){var r=l[n](e,t);if(!1!==r)return r}return"@"==n?(e.eatWhile(/[\w\\\-]/),w("def",e.current())):"="==n||("~"==n||"|"==n)&&e.eat("=")?w(null,"compare"):'"'==n||"'"==n?(t.tokenize=k(n),t.tokenize(e,t)):"#"==n?(e.eatWhile(/[\w\\\-]/),w("atom","hash")):"!"==n?(e.match(/^\s*\w*/),w("keyword","important")):/\d/.test(n)||"."==n&&e.eat(/\d/)?(e.eatWhile(/[\w.%]/),w("number","unit")):"-"!==n?/[,+>*\/]/.test(n)?w(null,"select-op"):"."==n&&e.match(/^-?[_a-z][_a-z0-9-]*/i)?w("qualifier","qualifier"):/[:;{}\[\]\(\)]/.test(n)?w(null,n):("u"==n||"U"==n)&&e.match(/rl(-prefix)?\(/i)||("d"==n||"D"==n)&&e.match("omain(",!0,!0)||("r"==n||"R"==n)&&e.match("egexp(",!0,!0)?(e.backUp(1),t.tokenize=C,w("property","word")):/[\w\\\-]/.test(n)?(e.eatWhile(/[\w\\\-]/),w("property","word")):w(null,null):/[\d.]/.test(e.peek())?(e.eatWhile(/[\w.%]/),w("number","unit")):e.match(/^-[\w\\\-]+/)?(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?w("variable-2","variable-definition"):w("variable-2","variable")):e.match(/^\w+-/)?w("meta","meta"):void 0})(e,t);return n&&"object"==typeof n&&(i=n[1],n=n[0]),o=n,"comment"!=i&&(t.state=N[t.state](i,e,t)),o},indent:function(e,t){var n=e.context,r=t&&t.charAt(0),i=n.indent;return"prop"!=n.type||"}"!=r&&")"!=r||(n=n.prev),n.prev&&("}"!=r||"block"!=n.type&&"top"!=n.type&&"interpolation"!=n.type&&"restricted_atBlock"!=n.type?(")"!=r||"parens"!=n.type&&"atBlock_parens"!=n.type)&&("{"!=r||"at"!=n.type&&"atBlock"!=n.type)||(i=Math.max(0,n.indent-a)):(n=n.prev,i=n.indent)),i},electricChars:"}",blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:b,fold:"brace"}});var n=["domain","regexp","url","url-prefix"],r=t(n),i=["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"],o=t(i),a=["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid","orientation","device-pixel-ratio","min-device-pixel-ratio","max-device-pixel-ratio","pointer","any-pointer","hover","any-hover"],l=t(a),s=["landscape","portrait","none","coarse","fine","on-demand","hover","interlace","progressive"],c=t(s),u=["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-gap","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-gap","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","justify-items","justify-self","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","place-content","place-items","place-self","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","user-select","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode"],f=t(u),d=["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"],h=t(d),p=t(["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]),m=t(["additive-symbols","fallback","negative","pad","prefix","range","speak-as","suffix","symbols","system"]),g=["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],v=t(g),y=["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","auto-flow","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","color","color-burn","color-dodge","column","column-reverse","compact","condensed","contain","content","contents","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","darken","dashed","decimal","decimal-leading-zero","default","default-button","dense","destination-atop","destination-in","destination-out","destination-over","devanagari","difference","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","exclusion","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","flex-end","flex-start","footnotes","forwards","from","geometricPrecision","georgian","graytext","grid","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hard-light","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","hue","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-grid","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","lighten","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","luminosity","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","multiply","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","opacity","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row","row-resize","row-reverse","rtl","run-in","running","s-resize","sans-serif","saturation","scale","scale3d","scaleX","scaleY","scaleZ","screen","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","self-start","self-end","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","soft-light","solid","somali","source-atop","source-in","source-out","source-over","space","space-around","space-between","space-evenly","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","system-ui","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","transform","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","unset","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","wrap","wrap-reverse","x-large","x-small","xor","xx-large","xx-small"],b=t(y),x=n.concat(i).concat(a).concat(s).concat(u).concat(d).concat(g).concat(y);function w(e,t){for(var n,r=!1;null!=(n=e.next());){if(r&&"/"==n){t.tokenize=null;break}r="*"==n}return["comment","comment"]}e.registerHelper("hintWords","css",x),e.defineMIME("text/css",{documentTypes:r,mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:f,nonStandardPropertyKeywords:h,fontProperties:p,counterDescriptors:m,colorKeywords:v,valueKeywords:b,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=w,w(e,t))}},name:"css"}),e.defineMIME("text/x-scss",{mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:f,nonStandardPropertyKeywords:h,colorKeywords:v,valueKeywords:b,fontProperties:p,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=w,w(e,t)):["operator","operator"]},":":function(e){return!!e.match(/\s*\{/,!1)&&[null,null]},$:function(e){return e.match(/^[\w-]+/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"]},"#":function(e){return!!e.eat("{")&&[null,"interpolation"]}},name:"css",helperType:"scss"}),e.defineMIME("text/x-less",{mediaTypes:o,mediaFeatures:l,mediaValueKeywords:c,propertyKeywords:f,nonStandardPropertyKeywords:h,colorKeywords:v,valueKeywords:b,fontProperties:p,allowNested:!0,lineComment:"//",tokenHooks:{"/":function(e,t){return e.eat("/")?(e.skipToEnd(),["comment","comment"]):e.eat("*")?(t.tokenize=w,w(e,t)):["operator","operator"]},"@":function(e){return e.eat("{")?[null,"interpolation"]:!e.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i,!1)&&(e.eatWhile(/[\w\\\-]/),e.match(/^\s*:/,!1)?["variable-2","variable-definition"]:["variable-2","variable"])},"&":function(){return["atom","atom"]}},name:"css",helperType:"less"}),e.defineMIME("text/x-gss",{documentTypes:r,mediaTypes:o,mediaFeatures:l,propertyKeywords:f,nonStandardPropertyKeywords:h,fontProperties:p,counterDescriptors:m,colorKeywords:v,valueKeywords:b,supportsAtComponent:!0,tokenHooks:{"/":function(e,t){return!!e.eat("*")&&(t.tokenize=w,w(e,t))}},name:"css",helperType:"gss"})}(n(0))},function(e,t,n){!function(e){"use strict";e.runMode=function(t,n,r,i){var o=e.getMode(e.defaults,n),a=/MSIE \d/.test(navigator.userAgent),l=a&&(null==document.documentMode||document.documentMode<9);if(r.appendChild){var s=i&&i.tabSize||e.defaults.tabSize,c=r,u=0;c.innerHTML="",r=function(e,t){if("\n"==e)return c.appendChild(document.createTextNode(l?"\r":e)),void(u=0);for(var n="",r=0;;){var i=e.indexOf("\t",r);if(-1==i){n+=e.slice(r),u+=e.length-r;break}u+=i-r,n+=e.slice(r,i);var o=s-u%s;u+=o;for(var a=0;a=s&&(o=r(a.indicatorOpen))}e.setGutterMarker(i,a.gutter,o),++l})}function o(e){var t=e.getViewport(),n=e.state.foldGutter;n&&(e.operation(function(){i(e,t.from,t.to)}),n.from=t.from,n.to=t.to)}function a(e,r,i){var o=e.state.foldGutter;if(o){var a=o.options;if(i==a.gutter){var l=n(e,r);l?l.clear():e.foldCode(t(r,0),a.rangeFinder)}}}function l(e){var t=e.state.foldGutter;if(t){var n=t.options;t.from=t.to=0,clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout(function(){o(e)},n.foldOnChangeTimeSpan||600)}}function s(e){var t=e.state.foldGutter;if(t){var n=t.options;clearTimeout(t.changeUpdate),t.changeUpdate=setTimeout(function(){var n=e.getViewport();t.from==t.to||n.from-t.to>20||t.from-n.to>20?o(e):e.operation(function(){n.fromt.to&&(i(e,t.to,n.to),t.to=n.to)})},n.updateViewportTimeSpan||400)}}function c(e,t){var n=e.state.foldGutter;if(n){var r=t.line;r>=n.from&&r=e.max))return e.ch=0,e.text=e.cm.getLine(++e.line),!0}function s(e){if(!(e.line<=e.min))return e.text=e.cm.getLine(--e.line),e.ch=e.text.length,!0}function c(e){for(;;){var t=e.text.indexOf(">",e.ch);if(-1==t){if(l(e))continue;return}if(a(e,t+1)){var n=e.text.lastIndexOf("/",t),r=n>-1&&!/\S/.test(e.text.slice(n+1,t));return e.ch=t+1,r?"selfClose":"regular"}e.ch=t+1}}function u(e){for(;;){var t=e.ch?e.text.lastIndexOf("<",e.ch-1):-1;if(-1==t){if(s(e))continue;return}if(a(e,t+1)){i.lastIndex=t,e.ch=t;var n=i.exec(e.text);if(n&&n.index==t)return n}else e.ch=t}}function f(e){for(;;){i.lastIndex=e.ch;var t=i.exec(e.text);if(!t){if(l(e))continue;return}if(a(e,t.index+1))return e.ch=t.index+t[0].length,t;e.ch=t.index+1}}function d(e){for(;;){var t=e.ch?e.text.lastIndexOf(">",e.ch-1):-1;if(-1==t){if(s(e))continue;return}if(a(e,t+1)){var n=e.text.lastIndexOf("/",t),r=n>-1&&!/\S/.test(e.text.slice(n+1,t));return e.ch=t+1,r?"selfClose":"regular"}e.ch=t}}function h(e,n){for(var r=[];;){var i,o=f(e),a=e.line,l=e.ch-(o?o[0].length:0);if(!o||!(i=c(e)))return;if("selfClose"!=i)if(o[1]){for(var s=r.length-1;s>=0;--s)if(r[s]==o[2]){r.length=s;break}if(s<0&&(!n||n==o[2]))return{tag:o[2],from:t(a,l),to:t(e.line,e.ch)}}else r.push(o[2])}}function p(e,n){for(var r=[];;){var i=d(e);if(!i)return;if("selfClose"!=i){var o=e.line,a=e.ch,l=u(e);if(!l)return;if(l[1])r.push(l[2]);else{for(var s=r.length-1;s>=0;--s)if(r[s]==l[2]){r.length=s;break}if(s<0&&(!n||n==l[2]))return{tag:l[2],from:t(e.line,e.ch),to:t(o,a)}}}else u(e)}}e.registerHelper("fold","xml",function(e,r){for(var i=new o(e,r.line,0);;){var a=f(i);if(!a||i.line!=r.line)return;var l=c(i);if(!l)return;if(!a[1]&&"selfClose"!=l){var s=t(i.line,i.ch),u=h(i,a[2]);return u&&n(u.from,s)>0?{from:s,to:u.from}:null}}}),e.findMatchingTag=function(e,r,i){var a=new o(e,r.line,r.ch,i);if(-1!=a.text.indexOf(">")||-1!=a.text.indexOf("<")){var l=c(a),s=l&&t(a.line,a.ch),f=l&&u(a);if(l&&f&&!(n(a,r)>0)){var d={from:t(a.line,a.ch),to:s,tag:f[2]};return"selfClose"==l?{open:d,close:null,at:"open"}:f[1]?{open:p(a,f[2]),close:d,at:"close"}:(a=new o(e,s.line,s.ch,i),{open:d,close:h(a,f[2]),at:"open"})}}},e.findEnclosingTag=function(e,t,n,r){for(var i=new o(e,t.line,t.ch,n);;){var a=p(i,r);if(!a)break;var l=new o(e,t.line,t.ch,n),s=h(l,a.tag);if(s)return{open:a,close:s}}},e.scanForClosingTag=function(e,t,n,r){var i=new o(e,t.line,t.ch,r?{from:0,to:r}:null);return h(i,n)}}(n(0))},function(e,t,n){!function(e){"use strict";e.registerGlobalHelper("fold","comment",function(e){return e.blockCommentStart&&e.blockCommentEnd},function(t,n){var r=t.getModeAt(n),i=r.blockCommentStart,o=r.blockCommentEnd;if(i&&o){for(var a,l=n.line,s=t.getLine(l),c=n.ch,u=0;;){var f=c<=0?-1:s.lastIndexOf(i,c-1);if(-1!=f){if(1==u&&ft.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));if(/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"keyword"!=r.type||"import"!=r.string)return null;for(var i=n,o=Math.min(t.lastLine(),n+10);i<=o;++i){var a=t.getLine(i),l=a.indexOf(";");if(-1!=l)return{startCh:r.end,end:e.Pos(i,l)}}}var i,o=n.line,a=r(o);if(!a||r(o-1)||(i=r(o-2))&&i.end.line==o-1)return null;for(var l=a.end;;){var s=r(l.line+1);if(null==s)break;l=s.end}return{from:t.clipPos(e.Pos(o,a.startCh+1)),to:l}}),e.registerHelper("fold","include",function(t,n){function r(n){if(nt.lastLine())return null;var r=t.getTokenAt(e.Pos(n,1));return/\S/.test(r.string)||(r=t.getTokenAt(e.Pos(n,r.end+1))),"meta"==r.type&&"#include"==r.string.slice(0,8)?r.start+8:void 0}var i=n.line,o=r(i);if(null==o||null!=r(i-1))return null;for(var a=i;;){var l=r(a+1);if(null==l)break;++a}return{from:e.Pos(i,o+1),to:t.clipPos(e.Pos(a))}})}(n(0))},function(e,t,n){!function(e){"use strict";var t=e.commands,n=e.Pos;function r(t,r){t.extendSelectionsBy(function(i){return t.display.shift||t.doc.extend||i.empty()?function(t,r,i){if(i<0&&0==r.ch)return t.clipPos(n(r.line-1));var o=t.getLine(r.line);if(i>0&&r.ch>=o.length)return t.clipPos(n(r.line+1,0));for(var a,l="start",s=r.ch,c=i<0?0:o.length,u=0;s!=c;s+=i,u++){var f=o.charAt(i<0?s-1:s),d="_"!=f&&e.isWordChar(f)?"w":"o";if("w"==d&&f.toUpperCase()==f&&(d="W"),"start"==l)"o"!=d&&(l="in",a=d);else if("in"==l&&a!=d){if("w"==a&&"W"==d&&i<0&&s--,"W"==a&&"w"==d&&i>0){a="w";continue}break}}return n(r.line,s)}(t.doc,i.head,r):r<0?i.from():i.to()})}function i(t,r){if(t.isReadOnly())return e.Pass;t.operation(function(){for(var e=t.listSelections().length,i=[],o=-1,a=0;a=n&&e.execCommand("goLineUp")}e.scrollTo(null,t.top-e.defaultTextHeight())},t.scrollLineDown=function(e){var t=e.getScrollInfo();if(!e.somethingSelected()){var n=e.lineAtHeight(t.top,"local")+1;e.getCursor().line<=n&&e.execCommand("goLineDown")}e.scrollTo(null,t.top+e.defaultTextHeight())},t.splitSelectionByLine=function(e){for(var t=e.listSelections(),r=[],i=0;io.line&&l==a.line&&0==a.ch||r.push({anchor:l==o.line?o:n(l,0),head:l==a.line?a:n(l)});e.setSelections(r,0)},t.singleSelectionTop=function(e){var t=e.listSelections()[0];e.setSelection(t.anchor,t.head,{scroll:!1})},t.selectLine=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;l--){var s=r[i[l]];if(!(c&&e.cmpPos(s.head,c)>0)){var u=o(t,s.head);c=u.from,t.replaceRange(n(u.word),u.from,u.to)}}})}function f(t){var n=t.getCursor("from"),r=t.getCursor("to");if(0==e.cmpPos(n,r)){var i=o(t,n);if(!i.word)return;n=i.from,r=i.to}return{from:n,to:r,query:t.getRange(n,r),word:i}}function d(e,t){var r=f(e);if(r){var i=r.query,o=e.getSearchCursor(i,t?r.to:r.from);(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):(o=e.getSearchCursor(i,t?n(e.firstLine(),0):e.clipPos(n(e.lastLine()))),(t?o.findNext():o.findPrevious())?e.setSelection(o.from(),o.to()):r.word&&e.setSelection(r.from,r.to))}}t.selectScope=function(e){s(e)||e.execCommand("selectAll")},t.selectBetweenBrackets=function(t){if(!s(t))return e.Pass},t.goToBracket=function(t){t.extendSelectionsBy(function(r){var i=t.scanForBracket(r.head,1);if(i&&0!=e.cmpPos(i.pos,r.head))return i.pos;var o=t.scanForBracket(r.head,-1);return o&&n(o.pos.line,o.pos.ch+1)||r.head})},t.swapLineUp=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.firstLine()-1,a=[],l=0;lo?i.push(c,u):i.length&&(i[i.length-1]=u),o=u}t.operation(function(){for(var e=0;et.lastLine()?t.replaceRange("\n"+l,n(t.lastLine()),null,"+swapLine"):t.replaceRange(l+"\n",n(o,0),null,"+swapLine")}t.setSelections(a),t.scrollIntoView()})},t.swapLineDown=function(t){if(t.isReadOnly())return e.Pass;for(var r=t.listSelections(),i=[],o=t.lastLine()+1,a=r.length-1;a>=0;a--){var l=r[a],s=l.to().line+1,c=l.from().line;0!=l.to().ch||l.empty()||s--,s=0;e-=2){var r=i[e],o=i[e+1],a=t.getLine(r);r==t.lastLine()?t.replaceRange("",n(r-1),n(r),"+swapLine"):t.replaceRange("",n(r,0),n(r+1,0),"+swapLine"),t.replaceRange(a+"\n",n(o,0),null,"+swapLine")}t.scrollIntoView()})},t.toggleCommentIndented=function(e){e.toggleComment({indent:!0})},t.joinLines=function(e){for(var t=e.listSelections(),r=[],i=0;i=0;o--){var a=r[o].head,l=t.getRange({line:a.line,ch:0},a),s=e.countColumn(l,null,t.getOption("tabSize")),c=t.findPosH(a,-1,"char",!1);if(l&&!/\S/.test(l)&&s%i==0){var u=new n(a.line,e.findColumn(l,s-i,i));u.ch!=a.ch&&(c=u)}t.replaceRange("",c,a,"+delete")}})},t.delLineRight=function(e){e.operation(function(){for(var t=e.listSelections(),r=t.length-1;r>=0;r--)e.replaceRange("",t[r].anchor,n(t[r].to().line),"+delete");e.scrollIntoView()})},t.upcaseAtCursor=function(e){u(e,function(e){return e.toUpperCase()})},t.downcaseAtCursor=function(e){u(e,function(e){return e.toLowerCase()})},t.setSublimeMark=function(e){e.state.sublimeMark&&e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor())},t.selectToSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&e.setSelection(e.getCursor(),t)},t.deleteToSublimeMark=function(t){var n=t.state.sublimeMark&&t.state.sublimeMark.find();if(n){var r=t.getCursor(),i=n;if(e.cmpPos(r,i)>0){var o=i;i=r,r=o}t.state.sublimeKilled=t.getRange(r,i),t.replaceRange("",r,i)}},t.swapWithSublimeMark=function(e){var t=e.state.sublimeMark&&e.state.sublimeMark.find();t&&(e.state.sublimeMark.clear(),e.state.sublimeMark=e.setBookmark(e.getCursor()),e.setCursor(t))},t.sublimeYank=function(e){null!=e.state.sublimeKilled&&e.replaceSelection(e.state.sublimeKilled,null,"paste")},t.showInCenter=function(e){var t=e.cursorCoords(null,"local");e.scrollTo(null,(t.top+t.bottom)/2-e.getScrollInfo().clientHeight/2)},t.findUnder=function(e){d(e,!0)},t.findUnderPrevious=function(e){d(e,!1)},t.findAllUnder=function(e){var t=f(e);if(t){for(var n=e.getSearchCursor(t.query),r=[],i=-1;n.findNext();)r.push({anchor:n.from(),head:n.to()}),n.from().line<=t.from.line&&n.from().ch<=t.from.ch&&i++;e.setSelections(r,i)}};var h=e.keyMap;h.macSublime={"Cmd-Left":"goLineStartSmart","Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Ctrl-Alt-Up":"scrollLineUp","Ctrl-Alt-Down":"scrollLineDown","Cmd-L":"selectLine","Shift-Cmd-L":"splitSelectionByLine",Esc:"singleSelectionTop","Cmd-Enter":"insertLineAfter","Shift-Cmd-Enter":"insertLineBefore","Cmd-D":"selectNextOccurrence","Shift-Cmd-Space":"selectScope","Shift-Cmd-M":"selectBetweenBrackets","Cmd-M":"goToBracket","Cmd-Ctrl-Up":"swapLineUp","Cmd-Ctrl-Down":"swapLineDown","Cmd-/":"toggleCommentIndented","Cmd-J":"joinLines","Shift-Cmd-D":"duplicateLine",F9:"sortLines","Cmd-F9":"sortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Cmd-F2":"toggleBookmark","Shift-Cmd-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Cmd-K Cmd-K":"delLineRight","Cmd-K Cmd-U":"upcaseAtCursor","Cmd-K Cmd-L":"downcaseAtCursor","Cmd-K Cmd-Space":"setSublimeMark","Cmd-K Cmd-A":"selectToSublimeMark","Cmd-K Cmd-W":"deleteToSublimeMark","Cmd-K Cmd-X":"swapWithSublimeMark","Cmd-K Cmd-Y":"sublimeYank","Cmd-K Cmd-C":"showInCenter","Cmd-K Cmd-G":"clearBookmarks","Cmd-K Cmd-Backspace":"delLineLeft","Cmd-K Cmd-0":"unfoldAll","Cmd-K Cmd-J":"unfoldAll","Ctrl-Shift-Up":"addCursorToPrevLine","Ctrl-Shift-Down":"addCursorToNextLine","Cmd-F3":"findUnder","Shift-Cmd-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Cmd-[":"fold","Shift-Cmd-]":"unfold","Cmd-I":"findIncremental","Shift-Cmd-I":"findIncrementalReverse","Cmd-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"macDefault"},e.normalizeKeyMap(h.macSublime),h.pcSublime={"Shift-Tab":"indentLess","Shift-Ctrl-K":"deleteLine","Alt-Q":"wrapLines","Ctrl-T":"transposeChars","Alt-Left":"goSubwordLeft","Alt-Right":"goSubwordRight","Ctrl-Up":"scrollLineUp","Ctrl-Down":"scrollLineDown","Ctrl-L":"selectLine","Shift-Ctrl-L":"splitSelectionByLine",Esc:"singleSelectionTop","Ctrl-Enter":"insertLineAfter","Shift-Ctrl-Enter":"insertLineBefore","Ctrl-D":"selectNextOccurrence","Shift-Ctrl-Space":"selectScope","Shift-Ctrl-M":"selectBetweenBrackets","Ctrl-M":"goToBracket","Shift-Ctrl-Up":"swapLineUp","Shift-Ctrl-Down":"swapLineDown","Ctrl-/":"toggleCommentIndented","Ctrl-J":"joinLines","Shift-Ctrl-D":"duplicateLine",F9:"sortLines","Ctrl-F9":"sortLinesInsensitive",F2:"nextBookmark","Shift-F2":"prevBookmark","Ctrl-F2":"toggleBookmark","Shift-Ctrl-F2":"clearBookmarks","Alt-F2":"selectBookmarks",Backspace:"smartBackspace","Ctrl-K Ctrl-K":"delLineRight","Ctrl-K Ctrl-U":"upcaseAtCursor","Ctrl-K Ctrl-L":"downcaseAtCursor","Ctrl-K Ctrl-Space":"setSublimeMark","Ctrl-K Ctrl-A":"selectToSublimeMark","Ctrl-K Ctrl-W":"deleteToSublimeMark","Ctrl-K Ctrl-X":"swapWithSublimeMark","Ctrl-K Ctrl-Y":"sublimeYank","Ctrl-K Ctrl-C":"showInCenter","Ctrl-K Ctrl-G":"clearBookmarks","Ctrl-K Ctrl-Backspace":"delLineLeft","Ctrl-K Ctrl-0":"unfoldAll","Ctrl-K Ctrl-J":"unfoldAll","Ctrl-Alt-Up":"addCursorToPrevLine","Ctrl-Alt-Down":"addCursorToNextLine","Ctrl-F3":"findUnder","Shift-Ctrl-F3":"findUnderPrevious","Alt-F3":"findAllUnder","Shift-Ctrl-[":"fold","Shift-Ctrl-]":"unfold","Ctrl-I":"findIncremental","Shift-Ctrl-I":"findIncrementalReverse","Ctrl-H":"replace",F3:"findNext","Shift-F3":"findPrev",fallthrough:"pcDefault"},e.normalizeKeyMap(h.pcSublime);var p=h.default==h.macDefault;h.sublime=p?h.macSublime:h.pcSublime}(n(0),n(1),n(4))},function(e,t,n){!function(e){"use strict";var t=[{keys:"",type:"keyToKey",toKeys:"h"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"h",context:"normal"},{keys:"",type:"keyToKey",toKeys:"W"},{keys:"",type:"keyToKey",toKeys:"B",context:"normal"},{keys:"",type:"keyToKey",toKeys:"w"},{keys:"",type:"keyToKey",toKeys:"b",context:"normal"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"s",type:"keyToKey",toKeys:"cl",context:"normal"},{keys:"s",type:"keyToKey",toKeys:"c",context:"visual"},{keys:"S",type:"keyToKey",toKeys:"cc",context:"normal"},{keys:"S",type:"keyToKey",toKeys:"VdO",context:"visual"},{keys:"",type:"keyToKey",toKeys:"0"},{keys:"",type:"keyToKey",toKeys:"$"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"j^",context:"normal"},{keys:"",type:"action",action:"toggleOverwrite",context:"insert"},{keys:"H",type:"motion",motion:"moveToTopLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"M",type:"motion",motion:"moveToMiddleLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"L",type:"motion",motion:"moveToBottomLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"h",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!1}},{keys:"l",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!0}},{keys:"j",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,linewise:!0}},{keys:"k",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,linewise:!0}},{keys:"gj",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!0}},{keys:"gk",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!1}},{keys:"w",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1}},{keys:"W",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1,bigWord:!0}},{keys:"e",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,inclusive:!0}},{keys:"E",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"b",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1}},{keys:"B",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1,bigWord:!0}},{keys:"ge",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,inclusive:!0}},{keys:"gE",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"{",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!1,toJumplist:!0}},{keys:"}",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!0,toJumplist:!0}},{keys:"(",type:"motion",motion:"moveBySentence",motionArgs:{forward:!1}},{keys:")",type:"motion",motion:"moveBySentence",motionArgs:{forward:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!1}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!0,explicitRepeat:!0}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!1,explicitRepeat:!0}},{keys:"gg",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!1,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"G",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!0,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"0",type:"motion",motion:"moveToStartOfLine"},{keys:"^",type:"motion",motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"+",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0}},{keys:"-",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,toFirstChar:!0}},{keys:"_",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0,repeatOffset:-1}},{keys:"$",type:"motion",motion:"moveToEol",motionArgs:{inclusive:!0}},{keys:"%",type:"motion",motion:"moveToMatchedSymbol",motionArgs:{inclusive:!0,toJumplist:!0}},{keys:"f",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"F",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!1}},{keys:"t",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"T",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!1}},{keys:";",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!0}},{keys:",",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!1}},{keys:"'",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0,linewise:!0}},{keys:"`",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0}},{keys:"]`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0}},{keys:"[`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1}},{keys:"]'",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0,linewise:!0}},{keys:"['",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1,linewise:!0}},{keys:"]p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0,matchIndent:!0}},{keys:"[p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0,matchIndent:!0}},{keys:"]",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!0,toJumplist:!0}},{keys:"[",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!1,toJumplist:!0}},{keys:"|",type:"motion",motion:"moveToColumn"},{keys:"o",type:"motion",motion:"moveToOtherHighlightedEnd",context:"visual"},{keys:"O",type:"motion",motion:"moveToOtherHighlightedEnd",motionArgs:{sameLine:!0},context:"visual"},{keys:"d",type:"operator",operator:"delete"},{keys:"y",type:"operator",operator:"yank"},{keys:"c",type:"operator",operator:"change"},{keys:">",type:"operator",operator:"indent",operatorArgs:{indentRight:!0}},{keys:"<",type:"operator",operator:"indent",operatorArgs:{indentRight:!1}},{keys:"g~",type:"operator",operator:"changeCase"},{keys:"gu",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},isEdit:!0},{keys:"gU",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},isEdit:!0},{keys:"n",type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:!0}},{keys:"N",type:"motion",motion:"findNext",motionArgs:{forward:!1,toJumplist:!0}},{keys:"x",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!0},operatorMotionArgs:{visualLine:!1}},{keys:"X",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!1},operatorMotionArgs:{visualLine:!0}},{keys:"D",type:"operatorMotion",operator:"delete",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"D",type:"operator",operator:"delete",operatorArgs:{linewise:!0},context:"visual"},{keys:"Y",type:"operatorMotion",operator:"yank",motion:"expandToLine",motionArgs:{linewise:!0},context:"normal"},{keys:"Y",type:"operator",operator:"yank",operatorArgs:{linewise:!0},context:"visual"},{keys:"C",type:"operatorMotion",operator:"change",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"C",type:"operator",operator:"change",operatorArgs:{linewise:!0},context:"visual"},{keys:"~",type:"operatorMotion",operator:"changeCase",motion:"moveByCharacters",motionArgs:{forward:!0},operatorArgs:{shouldMoveCursor:!0},context:"normal"},{keys:"~",type:"operator",operator:"changeCase",context:"visual"},{keys:"",type:"operatorMotion",operator:"delete",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1},context:"insert"},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!0}},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!1}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!0,linewise:!0}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!1,linewise:!0}},{keys:"a",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"charAfter"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"eol"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"endOfSelectedArea"},context:"visual"},{keys:"i",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"inplace"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"firstNonBlank"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"startOfSelectedArea"},context:"visual"},{keys:"o",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!0},context:"normal"},{keys:"O",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!1},context:"normal"},{keys:"v",type:"action",action:"toggleVisualMode"},{keys:"V",type:"action",action:"toggleVisualMode",actionArgs:{linewise:!0}},{keys:"",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"gv",type:"action",action:"reselectLastSelection"},{keys:"J",type:"action",action:"joinLines",isEdit:!0},{keys:"p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0}},{keys:"P",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0}},{keys:"r",type:"action",action:"replace",isEdit:!0},{keys:"@",type:"action",action:"replayMacro"},{keys:"q",type:"action",action:"enterMacroRecordMode"},{keys:"R",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{replace:!0}},{keys:"u",type:"action",action:"undo",context:"normal"},{keys:"u",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},context:"visual",isEdit:!0},{keys:"U",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},context:"visual",isEdit:!0},{keys:"",type:"action",action:"redo"},{keys:"m",type:"action",action:"setMark"},{keys:'"',type:"action",action:"setRegister"},{keys:"zz",type:"action",action:"scrollToCursor",actionArgs:{position:"center"}},{keys:"z.",type:"action",action:"scrollToCursor",actionArgs:{position:"center"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"zt",type:"action",action:"scrollToCursor",actionArgs:{position:"top"}},{keys:"z",type:"action",action:"scrollToCursor",actionArgs:{position:"top"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"z-",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"}},{keys:"zb",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:".",type:"action",action:"repeatLastEdit"},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!0,backtrack:!1}},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!1,backtrack:!1}},{keys:"",type:"action",action:"indent",actionArgs:{indentRight:!0},context:"insert"},{keys:"",type:"action",action:"indent",actionArgs:{indentRight:!1},context:"insert"},{keys:"a",type:"motion",motion:"textObjectManipulation"},{keys:"i",type:"motion",motion:"textObjectManipulation",motionArgs:{textObjectInner:!0}},{keys:"/",type:"search",searchArgs:{forward:!0,querySrc:"prompt",toJumplist:!0}},{keys:"?",type:"search",searchArgs:{forward:!1,querySrc:"prompt",toJumplist:!0}},{keys:"*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"g*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:"g#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:":",type:"ex"}],n=[{name:"colorscheme",shortName:"colo"},{name:"map"},{name:"imap",shortName:"im"},{name:"nmap",shortName:"nm"},{name:"vmap",shortName:"vm"},{name:"unmap"},{name:"write",shortName:"w"},{name:"undo",shortName:"u"},{name:"redo",shortName:"red"},{name:"set",shortName:"se"},{name:"set",shortName:"se"},{name:"setlocal",shortName:"setl"},{name:"setglobal",shortName:"setg"},{name:"sort",shortName:"sor"},{name:"substitute",shortName:"s",possiblyAsync:!0},{name:"nohlsearch",shortName:"noh"},{name:"yank",shortName:"y"},{name:"delmarks",shortName:"delm"},{name:"registers",shortName:"reg",excludeFromCommandHistory:!0},{name:"global",shortName:"g"}],r=e.Pos;e.Vim=function(){function i(t,n){this==e.keyMap.vim&&(e.rmClass(t.getWrapperElement(),"cm-fat-cursor"),"contenteditable"==t.getOption("inputStyle")&&null!=document.body.style.caretColor&&(function(e){var t=e.state.fatCursorMarks;if(t)for(var n=0;n")}(t);if(!r)return!1;var i=e.Vim.findKey(n,r);return"function"==typeof i&&e.signal(n,"vim-keypress",r),i}}e.defineOption("vimMode",!1,function(t,n,r){n&&"vim"!=t.getOption("keyMap")?t.setOption("keyMap","vim"):!n&&r!=e.Init&&/^vim/.test(t.getOption("keyMap"))&&t.setOption("keyMap","default")});var c={Shift:"S",Ctrl:"C",Alt:"A",Cmd:"D",Mod:"A"},u={Enter:"CR",Backspace:"BS",Delete:"Del",Insert:"Ins"};function f(e){var t=e.state.vim;return t.onPasteFn||(t.onPasteFn=function(){t.insertMode||(e.setCursor(J(e.getCursor(),0,1)),G.enterInsertMode(e,{},t))}),t.onPasteFn}var d=/[\d]/,h=[e.isWordChar,function(t){return t&&!e.isWordChar(t)&&!/\s/.test(t)}],p=[function(e){return/\S/.test(e)}];function m(e,t){for(var n=[],r=e;r"]),x=[].concat(g,v,y,["-",'"',".",":","/"]);function w(e,t){return t>=e.firstLine()&&t<=e.lastLine()}function k(e){return/^[a-z]$/.test(e)}function C(e){return/^[A-Z]$/.test(e)}function S(e){return/^\s*$/.test(e)}function L(e){return-1!=".?!".indexOf(e)}function M(e,t){for(var n=0;nn?t=n:t0?1:-1,u=o.getCursor();do{if((l=i[(e+(t+=c))%e])&&(s=l.find())&&!te(u,s))break}while(tr)}return l}}},R=function(e){return e?{changes:e.changes,expectCursorActivityForChange:e.expectCursorActivityForChange}:{changes:[],expectCursorActivityForChange:!1}};function B(){this.latestRegister=void 0,this.isPlaying=!1,this.isRecording=!1,this.replaySearchQueries=[],this.onRecordingDone=void 0,this.lastInsertModeChanges=R()}function D(e){return e.state.vim||(e.state.vim={inputState:new z,lastEditInputState:void 0,lastEditActionCommand:void 0,lastHPos:-1,lastHSPos:-1,lastMotion:null,marks:{},fakeCursor:null,insertMode:!1,insertModeRepeat:void 0,visualMode:!1,visualLine:!1,visualBlock:!1,lastSelection:null,lastPastedText:null,sel:{},options:{}}),e.state.vim}function F(){for(var e in E={searchQuery:null,searchIsReversed:!1,lastSubstituteReplacePart:void 0,jumpList:I(),macroModeState:new B,lastCharacterSearch:{increment:0,forward:!0,selectedCharacter:""},registerController:new K({}),searchHistoryController:new j,exCommandHistoryController:new j},T){var t=T[e];t.value=t.defaultValue}}B.prototype={exitMacroRecordMode:function(){var e=E.macroModeState;e.onRecordingDone&&e.onRecordingDone(),e.onRecordingDone=void 0,e.isRecording=!1},enterMacroRecordMode:function(e,t){var n=E.registerController.getRegister(t);n&&(n.clear(),this.latestRegister=t,e.openDialog&&(this.onRecordingDone=e.openDialog("(recording)["+t+"]",null,{bottom:!0})),this.isRecording=!0)}};var W={buildKeyMap:function(){},getRegisterController:function(){return E.registerController},resetVimGlobalState_:F,getVimGlobalState_:function(){return E},maybeInitVimState_:D,suppressErrorLogging:!1,InsertModeKey:Qe,map:function(e,t,n){Ve.map(e,t,n)},unmap:function(e,t){Ve.unmap(e,t)},setOption:O,getOption:N,defineOption:A,defineEx:function(e,t,n){if(t){if(0!==e.indexOf(t))throw new Error('(Vim.defineEx) "'+t+'" is not a prefix of "'+e+'", command not registered')}else t=e;Ue[e]=n,Ve.commandMap_[t]={name:e,shortName:t,type:"api"}},handleKey:function(e,t,n){var r=this.findKey(e,t,n);if("function"==typeof r)return r()},findKey:function(n,r,i){var o,a=D(n);function l(){var e=E.macroModeState;if(e.isRecording){if("q"==r)return e.exitMacroRecordMode(),_(n),!0;"mapping"!=i&&function(e,t){if(!e.isPlaying){var n=e.latestRegister,r=E.registerController.getRegister(n);r&&r.pushText(t)}}(e,r)}}function s(){if(""==r)return _(n),a.visualMode?pe(n):a.insertMode&&qe(n),!0}return!1===(o=a.insertMode?function(){if(s())return!0;for(var e=a.inputState.keyBuffer=a.inputState.keyBuffer+r,i=1==r.length,o=U.matchCommand(e,t,a.inputState,"insert");e.length>1&&"full"!=o.type;){var e=a.inputState.keyBuffer=e.slice(1),l=U.matchCommand(e,t,a.inputState,"insert");"none"!=l.type&&(o=l)}if("none"==o.type)return _(n),!1;if("partial"==o.type)return P&&window.clearTimeout(P),P=window.setTimeout(function(){a.insertMode&&a.inputState.keyBuffer&&_(n)},N("insertModeEscKeysTimeout")),!i;if(P&&window.clearTimeout(P),i){for(var c=n.listSelections(),u=0;u|<\w+>|./.exec(t),r=i[0],t=t.substring(i.index+r.length),e.Vim.handleKey(n,r,"mapping")}(o.toKeys):U.processCommand(n,a,o)}catch(t){throw n.state.vim=void 0,D(n),e.Vim.suppressErrorLogging||console.log(t),t}return!0})}},handleEx:function(e,t){Ve.processCommand(e,t)},defineMotion:function(e,t){V[e]=t},defineAction:function(e,t){G[e]=t},defineOperator:function(e,t){$[e]=t},mapCommand:function(e,t,n,r,i){var o={keys:e,type:t};for(var a in o[t]=n,o[t+"Args"]=r,i)o[a]=i[a];$e(o)},_mapCommand:$e,defineRegister:function(e,t){var n=E.registerController.registers;if(!e||1!=e.length)throw Error("Register name must be 1 character");if(n[e])throw Error("Register already defined "+e);n[e]=t,x.push(e)},exitVisualMode:pe,exitInsertMode:qe};function z(){this.prefixRepeat=[],this.motionRepeat=[],this.operator=null,this.operatorArgs=null,this.motion=null,this.motionArgs=null,this.keyBuffer=[],this.registerName=null}function _(t,n){t.state.vim.inputState=new z,e.signal(t,"vim-command-done",n)}function H(e,t,n){this.clear(),this.keyBuffer=[e||""],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!!t,this.blockwise=!!n}function K(e){this.registers=e,this.unnamedRegister=e['"']=new H,e["."]=new H,e[":"]=new H,e["/"]=new H}function j(){this.historyBuffer=[],this.iterator=0,this.initialPrefix=null}z.prototype.pushRepeatDigit=function(e){this.operator?this.motionRepeat=this.motionRepeat.concat(e):this.prefixRepeat=this.prefixRepeat.concat(e)},z.prototype.getRepeat=function(){var e=0;return(this.prefixRepeat.length>0||this.motionRepeat.length>0)&&(e=1,this.prefixRepeat.length>0&&(e*=parseInt(this.prefixRepeat.join(""),10)),this.motionRepeat.length>0&&(e*=parseInt(this.motionRepeat.join(""),10))),e},H.prototype={setText:function(e,t,n){this.keyBuffer=[e||""],this.linewise=!!t,this.blockwise=!!n},pushText:function(e,t){t&&(this.linewise||this.keyBuffer.push("\n"),this.linewise=!0),this.keyBuffer.push(e)},pushInsertModeChanges:function(e){this.insertModeChanges.push(R(e))},pushSearchQuery:function(e){this.searchQueries.push(e)},clear:function(){this.keyBuffer=[],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!1},toString:function(){return this.keyBuffer.join("")}},K.prototype={pushText:function(e,t,n,r,i){r&&"\n"!==n.charAt(n.length-1)&&(n+="\n");var o=this.isValidRegister(e)?this.getRegister(e):null;if(o){var a=C(e);a?o.pushText(n,r):o.setText(n,r,i),this.unnamedRegister.setText(o.toString(),r)}else{switch(t){case"yank":this.registers[0]=new H(n,r,i);break;case"delete":case"change":-1==n.indexOf("\n")?this.registers["-"]=new H(n,r):(this.shiftNumericRegisters_(),this.registers[1]=new H(n,r))}this.unnamedRegister.setText(n,r,i)}},getRegister:function(e){return this.isValidRegister(e)?(e=e.toLowerCase(),this.registers[e]||(this.registers[e]=new H),this.registers[e]):this.unnamedRegister},isValidRegister:function(e){return e&&M(e,x)},shiftNumericRegisters_:function(){for(var e=9;e>=2;e--)this.registers[e]=this.getRegister(""+(e-1))}},j.prototype={nextMatch:function(e,t){var n=this.historyBuffer,r=t?-1:1;null===this.initialPrefix&&(this.initialPrefix=e);for(var i=this.iterator+r;t?i>=0:i=n.length?(this.iterator=n.length,this.initialPrefix):i<0?e:void 0},pushInput:function(e){var t=this.historyBuffer.indexOf(e);t>-1&&this.historyBuffer.splice(t,1),e.length&&this.historyBuffer.push(e)},reset:function(){this.initialPrefix=null,this.iterator=this.historyBuffer.length}};var U={matchCommand:function(e,t,n,r){var i,o=function(e,t,n,r){for(var i,o=[],a=[],l=0;l"==i.keys.slice(-11)){var s=function(e){var t=/^.*(<[^>]+>)$/.exec(e),n=t?t[1]:e.slice(-1);if(n.length>1)switch(n){case"":n="\n";break;case"":n=" ";break;default:n=""}return n}(e);if(!s)return{type:"none"};n.selectedCharacter=s}return{type:"full",command:i}},processCommand:function(e,t,n){switch(t.inputState.repeatOverride=n.repeatOverride,n.type){case"motion":this.processMotion(e,t,n);break;case"operator":this.processOperator(e,t,n);break;case"operatorMotion":this.processOperatorMotion(e,t,n);break;case"action":this.processAction(e,t,n);break;case"search":this.processSearch(e,t,n);break;case"ex":case"keyToEx":this.processEx(e,t,n)}},processMotion:function(e,t,n){t.inputState.motion=n.motion,t.inputState.motionArgs=Y(n.motionArgs),this.evalInput(e,t)},processOperator:function(e,t,n){var r=t.inputState;if(r.operator){if(r.operator==n.operator)return r.motion="expandToLine",r.motionArgs={linewise:!0},void this.evalInput(e,t);_(e)}r.operator=n.operator,r.operatorArgs=Y(n.operatorArgs),t.visualMode&&this.evalInput(e,t)},processOperatorMotion:function(e,t,n){var r=t.visualMode,i=Y(n.operatorMotionArgs);i&&r&&i.visualLine&&(t.visualLine=!0),this.processOperator(e,t,n),r||this.processMotion(e,t,n)},processAction:function(e,t,n){var r=t.inputState,i=r.getRepeat(),o=!!i,a=Y(n.actionArgs)||{};r.selectedCharacter&&(a.selectedCharacter=r.selectedCharacter),n.operator&&this.processOperator(e,t,n),n.motion&&this.processMotion(e,t,n),(n.motion||n.operator)&&this.evalInput(e,t),a.repeat=i||1,a.repeatIsExplicit=o,a.registerName=r.registerName,_(e),t.lastMotion=null,n.isEdit&&this.recordLastEdit(t,r,n),G[n.action](e,a,t)},processSearch:function(t,n,r){if(t.getSearchCursor){var i=r.searchArgs.forward,o=r.searchArgs.wholeWordOnly;Te(t).setReversed(!i);var a=i?"/":"?",l=Te(t).getQuery(),s=t.getScrollInfo();switch(r.searchArgs.querySrc){case"prompt":var c=E.macroModeState;if(c.isPlaying){var u=c.replaySearchQueries.shift();h(u,!0,!1)}else De(t,{onClose:function(e){t.scrollTo(s.left,s.top),h(e,!0,!0);var n=E.macroModeState;n.isRecording&&function(e,t){if(!e.isPlaying){var n=e.latestRegister,r=E.registerController.getRegister(n);r&&r.pushSearchQuery&&r.pushSearchQuery(t)}}(n,e)},prefix:a,desc:Be,onKeyUp:function(n,r,o){var a,l,c,u=e.keyName(n);"Up"==u||"Down"==u?(a="Up"==u,l=n.target?n.target.selectionEnd:0,r=E.searchHistoryController.nextMatch(r,a)||"",o(r),l&&n.target&&(n.target.selectionEnd=n.target.selectionStart=Math.min(l,n.target.value.length))):"Left"!=u&&"Right"!=u&&"Ctrl"!=u&&"Alt"!=u&&"Shift"!=u&&E.searchHistoryController.reset();try{c=Fe(t,r,!0,!0)}catch(n){}c?t.scrollIntoView(ze(t,!i,c),30):(_e(t),t.scrollTo(s.left,s.top))},onKeyDown:function(n,r,i){var o=e.keyName(n);"Esc"==o||"Ctrl-C"==o||"Ctrl-["==o||"Backspace"==o&&""==r?(E.searchHistoryController.pushInput(r),E.searchHistoryController.reset(),Fe(t,l),_e(t),t.scrollTo(s.left,s.top),e.e_stop(n),_(t),i(),t.focus()):"Up"==o||"Down"==o?e.e_stop(n):"Ctrl-U"==o&&(e.e_stop(n),i(""))}});break;case"wordUnderCursor":var f=ge(t,!1,0,!1,!0),d=!0;if(f||(f=ge(t,!1,0,!1,!1),d=!1),!f)return;var u=t.getLine(f.start.line).substring(f.start.ch,f.end.ch);u=d&&o?"\\b"+u+"\\b":u.replace(/([.?*+$\[\]\/\\(){}|\-])/g,"\\$1"),E.jumpList.cachedCursor=t.getCursor(),t.setCursor(f.start),h(u,!0,!1)}}function h(e,i,o){E.searchHistoryController.pushInput(e),E.searchHistoryController.reset();try{Fe(t,e,i,o)}catch(n){return Re(t,"Invalid regex: "+e),void _(t)}U.processMotion(t,n,{type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:r.searchArgs.toJumplist}})}},processEx:function(t,n,r){function i(e){E.exCommandHistoryController.pushInput(e),E.exCommandHistoryController.reset(),Ve.processCommand(t,e)}function o(n,r,i){var o,a,l=e.keyName(n);("Esc"==l||"Ctrl-C"==l||"Ctrl-["==l||"Backspace"==l&&""==r)&&(E.exCommandHistoryController.pushInput(r),E.exCommandHistoryController.reset(),e.e_stop(n),_(t),i(),t.focus()),"Up"==l||"Down"==l?(e.e_stop(n),o="Up"==l,a=n.target?n.target.selectionEnd:0,r=E.exCommandHistoryController.nextMatch(r,o)||"",i(r),a&&n.target&&(n.target.selectionEnd=n.target.selectionStart=Math.min(a,n.target.value.length))):"Ctrl-U"==l?(e.e_stop(n),i("")):"Left"!=l&&"Right"!=l&&"Ctrl"!=l&&"Alt"!=l&&"Shift"!=l&&E.exCommandHistoryController.reset()}"keyToEx"==r.type?Ve.processCommand(t,r.exArgs.input):n.visualMode?De(t,{onClose:i,prefix:":",value:"'<,'>",onKeyDown:o,selectValueOnOpen:!1}):De(t,{onClose:i,prefix:":",onKeyDown:o})},evalInput:function(e,t){var n,i,o,a=t.inputState,l=a.motion,s=a.motionArgs||{},c=a.operator,u=a.operatorArgs||{},f=a.registerName,d=t.sel,h=ee(t.visualMode?X(e,d.head):e.getCursor("head")),p=ee(t.visualMode?X(e,d.anchor):e.getCursor("anchor")),m=ee(h),g=ee(p);if(c&&this.recordLastEdit(t,a),(o=void 0!==a.repeatOverride?a.repeatOverride:a.getRepeat())>0&&s.explicitRepeat?s.repeatIsExplicit=!0:(s.noRepeat||!s.explicitRepeat&&0===o)&&(o=1,s.repeatIsExplicit=!1),a.selectedCharacter&&(s.selectedCharacter=u.selectedCharacter=a.selectedCharacter),s.repeat=o,_(e),l){var v=V[l](e,h,s,t);if(t.lastMotion=V[l],!v)return;if(s.toJumplist){var y=E.jumpList,b=y.cachedCursor;b?(ve(e,b,v),delete y.cachedCursor):ve(e,h,v)}v instanceof Array?(i=v[0],n=v[1]):n=v,n||(n=ee(h)),t.visualMode?(t.visualBlock&&n.ch===1/0||(n=X(e,n,t.visualBlock)),i&&(i=X(e,i,!0)),i=i||g,d.anchor=i,d.head=n,de(e),Ce(e,t,"<",ne(i,n)?i:n),Ce(e,t,">",ne(i,n)?n:i)):c||(n=X(e,n),e.setCursor(n.line,n.ch))}if(c){if(u.lastSel){i=g;var x=u.lastSel,w=Math.abs(x.head.line-x.anchor.line),k=Math.abs(x.head.ch-x.anchor.ch);n=x.visualLine?r(g.line+w,g.ch):x.visualBlock?r(g.line+w,g.ch+k):x.head.line==x.anchor.line?r(g.line,g.ch+k):r(g.line+w,g.ch),t.visualMode=!0,t.visualLine=x.visualLine,t.visualBlock=x.visualBlock,d=t.sel={anchor:i,head:n},de(e)}else t.visualMode&&(u.lastSel={anchor:ee(d.anchor),head:ee(d.head),visualBlock:t.visualBlock,visualLine:t.visualLine});var C,L,M,T,A;if(t.visualMode){if(C=re(d.head,d.anchor),L=ie(d.head,d.anchor),M=t.visualLine||u.linewise,T=t.visualBlock?"block":M?"line":"char",A=he(e,{anchor:C,head:L},T),M){var O=A.ranges;if("block"==T)for(var N=0;N0&&o&&S(o);o=i.pop())n.line--,n.ch=0;o?(n.line--,n.ch=ae(e,n.line)):n.ch=0}}(e,C,L),T="char";var I=!s.inclusive||M;A=he(e,{anchor:C,head:L},T,I)}e.setSelections(A.ranges,A.primary),t.lastMotion=null,u.repeat=o,u.registerName=f,u.linewise=M;var R=$[c](e,u,A.ranges,g,n);t.visualMode&&pe(e,null!=R),R&&e.setCursor(R)}},recordLastEdit:function(e,t,n){var r=E.macroModeState;r.isPlaying||(e.lastEditInputState=t,e.lastEditActionCommand=n,r.lastInsertModeChanges.changes=[],r.lastInsertModeChanges.expectCursorActivityForChange=!1)}},V={moveToTopLine:function(e,t,n){var i=He(e).top+n.repeat-1;return r(i,me(e.getLine(i)))},moveToMiddleLine:function(e){var t=He(e),n=Math.floor(.5*(t.top+t.bottom));return r(n,me(e.getLine(n)))},moveToBottomLine:function(e,t,n){var i=He(e).bottom-n.repeat+1;return r(i,me(e.getLine(i)))},expandToLine:function(e,t,n){var i=t;return r(i.line+n.repeat-1,1/0)},findNext:function(e,t,n){var r=Te(e),i=r.getQuery();if(i){var o=!n.forward;return o=r.isReversed()?!o:o,We(e,i),ze(e,o,i,n.repeat)}},goToMark:function(e,t,n,r){var i=Ke(e,r,n.selectedCharacter);return i?n.linewise?{line:i.line,ch:me(e.getLine(i.line))}:i:null},moveToOtherHighlightedEnd:function(e,t,n,i){if(i.visualBlock&&n.sameLine){var o=i.sel;return[X(e,r(o.anchor.line,o.head.ch)),X(e,r(o.head.line,o.anchor.ch))]}return[i.sel.head,i.sel.anchor]},jumpToMark:function(e,t,n,i){for(var o=t,a=0;au&&o.line==u?this.moveToEol(e,t,n,i):(n.toFirstChar&&(a=me(e.getLine(s)),i.lastHPos=a),i.lastHSPos=e.charCoords(r(s,a),"div").left,r(s,a))},moveByDisplayLines:function(e,t,n,i){var o=t;switch(i.lastMotion){case this.moveByDisplayLines:case this.moveByScroll:case this.moveByLines:case this.moveToColumn:case this.moveToEol:break;default:i.lastHSPos=e.charCoords(o,"div").left}var a=n.repeat,l=e.findPosV(o,n.forward?a:-a,"line",i.lastHSPos);if(l.hitSide)if(n.forward)var s=e.charCoords(l,"div"),c={top:s.top+8,left:i.lastHSPos},l=e.coordsChar(c,"div");else{var u=e.charCoords(r(e.firstLine(),0),"div");u.left=i.lastHSPos,l=e.coordsChar(u,"div")}return i.lastHPos=l.ch,l},moveByPage:function(e,t,n){var r=t,i=n.repeat;return e.findPosV(r,n.forward?i:-i,"page")},moveByParagraph:function(e,t,n){var r=n.forward?1:-1;return Le(e,t,n.repeat,r)},moveBySentence:function(e,t,n){var i=n.forward?1:-1;return function(e,t,n,i){function o(e,t){if(t.pos+t.dir<0||t.pos+t.dir>=t.line.length){if(t.ln+=t.dir,!w(e,t.ln))return t.line=null,t.ln=null,void(t.pos=null);t.line=e.getLine(t.ln),t.pos=t.dir>0?0:t.line.length-1}else t.pos+=t.dir}function a(e,t,n,r){var i=e.getLine(t),a=""===i,l={line:i,ln:t,pos:n,dir:r},s={ln:l.ln,pos:l.pos},c=""===l.line;for(o(e,l);null!==l.line;){if(s.ln=l.ln,s.pos=l.pos,""===l.line&&!c)return{ln:l.ln,pos:l.pos};if(a&&""!==l.line&&!S(l.line[l.pos]))return{ln:l.ln,pos:l.pos};!L(l.line[l.pos])||a||l.pos!==l.line.length-1&&!S(l.line[l.pos+1])||(a=!0),o(e,l)}var i=e.getLine(s.ln);s.pos=0;for(var u=i.length-1;u>=0;--u)if(!S(i[u])){s.pos=u;break}return s}function l(e,t,n,r){var i=e.getLine(t),a={line:i,ln:t,pos:n,dir:r},l={ln:a.ln,pos:null},s=""===a.line;for(o(e,a);null!==a.line;){if(""===a.line&&!s)return null!==l.pos?l:{ln:a.ln,pos:a.pos};if(L(a.line[a.pos])&&null!==l.pos&&(a.ln!==l.ln||a.pos+1!==l.pos))return l;""===a.line||S(a.line[a.pos])||(s=!1,l={ln:a.ln,pos:a.pos}),o(e,a)}var i=e.getLine(l.ln);l.pos=0;for(var c=0;c0;)s=i<0?l(e,s.ln,s.pos,i):a(e,s.ln,s.pos,i),n--;return r(s.ln,s.pos)}(e,t,n.repeat,i)},moveByScroll:function(e,t,n,r){var i=e.getScrollInfo(),o=null,a=n.repeat;a||(a=i.clientHeight/(2*e.defaultTextHeight()));var l=e.charCoords(t,"local");n.repeat=a;var o=V.moveByDisplayLines(e,t,n,r);if(!o)return null;var s=e.charCoords(o,"local");return e.scrollTo(null,i.top+s.top-l.top),o},moveByWords:function(e,t,n){return function(e,t,n,i,o,a){var l=ee(t),s=[];(i&&!o||!i&&o)&&n++;for(var c=!(i&&o),u=0;u0)f.index=0;else{var m=f.lineText.length;f.index=m>0?m-1:0}f.nextCh=f.lineText.charAt(f.index)}p(f)&&(o.line=c,o.ch=f.index,t--)}return f.nextCh||f.curMoveThrough?r(c,f.index):o}(e,i,n.forward,n.selectedCharacter)||t},moveToColumn:function(e,t,n,i){var o=n.repeat;return i.lastHPos=o-1,i.lastHSPos=e.charCoords(t,"div").left,function(e,t){var n=e.getCursor().line;return X(e,r(n,t-1))}(e,o)},moveToEol:function(e,t,n,i){var o=t;i.lastHPos=1/0;var a=r(o.line+n.repeat-1,1/0),l=e.clipPos(a);return l.ch--,i.lastHSPos=e.charCoords(l,"div").left,a},moveToFirstNonWhiteSpaceCharacter:function(e,t){var n=t;return r(n.line,me(e.getLine(n.line)))},moveToMatchedSymbol:function(e,t){for(var n,i=t,o=i.line,a=i.ch,l=e.getLine(o);aa.ch||o.line>a.line){var f=o;o=a,a=f}return i?a.ch+=1:o.ch+=1,{start:o,end:a}}(e,t,o,l);else if({"'":!0,'"':!0}[o])a=function(e,t,n,i){var o,a,l,s,c=ee(t),u=e.getLine(c.line).split(""),f=u.indexOf(n);if(c.ch-1&&!o;l--)u[l]==n&&(o=l+1);else o=c.ch+1;if(o&&!a)for(l=o,s=u.length;lt.lastLine()&&n.linewise&&!p?t.replaceRange("",h,u):t.replaceRange("",c,u),n.linewise&&(p||(t.setCursor(h),e.commands.newlineAndIndent(t)),c.ch=Number.MAX_VALUE),o=c}E.registerController.pushText(n.registerName,"change",a,n.linewise,i.length>1),G.enterInsertMode(t,{head:o},t.state.vim)},delete:function(e,t,n){var i,o,a=e.state.vim;if(a.visualBlock){o=e.getSelection();var l=q("",n.length);e.replaceSelections(l),i=n[0].anchor}else{var s=n[0].anchor,c=n[0].head;t.linewise&&c.line!=e.firstLine()&&s.line==e.lastLine()&&s.line==c.line-1&&(s.line==e.firstLine()?s.ch=0:s=r(s.line-1,ae(e,s.line-1))),o=e.getRange(s,c),e.replaceRange("",s,c),i=s,t.linewise&&(i=V.moveToFirstNonWhiteSpaceCharacter(e,s))}E.registerController.pushText(t.registerName,"delete",o,t.linewise,a.visualBlock);var u=a.insertMode;return X(e,i,u)},indent:function(e,t,n){var r=e.state.vim,i=n[0].anchor.line,o=r.visualBlock?n[n.length-1].anchor.line:n[0].head.line,a=r.visualMode?t.repeat:1;t.linewise&&o--;for(var l=i;l<=o;l++)for(var s=0;sc.top?(s.line+=(l-c.top)/i,s.line=Math.ceil(s.line),e.setCursor(s),c=e.charCoords(s,"local"),e.scrollTo(null,c.top)):e.scrollTo(null,l);else{var u=l+e.getScrollInfo().clientHeight;u=a.anchor.line?J(a.head,0,1):r(a.anchor.line,0);else if("inplace"==o&&i.visualMode)return;t.setOption("disableInput",!1),n&&n.replace?(t.toggleOverwrite(!0),t.setOption("keyMap","vim-replace"),e.signal(t,"vim-mode-change",{mode:"replace"})):(t.toggleOverwrite(!1),t.setOption("keyMap","vim-insert"),e.signal(t,"vim-mode-change",{mode:"insert"})),E.macroModeState.isPlaying||(t.on("change",Xe),e.on(t.getInputField(),"keydown",Ze)),i.visualMode&&pe(t),ue(t,l,s)}},toggleVisualMode:function(t,n,i){var o,a=n.repeat,l=t.getCursor();i.visualMode?i.visualLine^n.linewise||i.visualBlock^n.blockwise?(i.visualLine=!!n.linewise,i.visualBlock=!!n.blockwise,e.signal(t,"vim-mode-change",{mode:"visual",subMode:i.visualLine?"linewise":i.visualBlock?"blockwise":""}),de(t)):pe(t):(i.visualMode=!0,i.visualLine=!!n.linewise,i.visualBlock=!!n.blockwise,o=X(t,r(l.line,l.ch+a-1),!0),i.sel={anchor:l,head:o},e.signal(t,"vim-mode-change",{mode:"visual",subMode:i.visualLine?"linewise":i.visualBlock?"blockwise":""}),de(t),Ce(t,i,"<",re(l,o)),Ce(t,i,">",ie(l,o)))},reselectLastSelection:function(t,n,r){var i=r.lastSelection;if(r.visualMode&&fe(t,r),i){var o=i.anchorMark.find(),a=i.headMark.find();if(!o||!a)return;r.sel={anchor:o,head:a},r.visualMode=!0,r.visualLine=i.visualLine,r.visualBlock=i.visualBlock,de(t),Ce(t,r,"<",re(o,a)),Ce(t,r,">",ie(o,a)),e.signal(t,"vim-mode-change",{mode:"visual",subMode:r.visualLine?"linewise":r.visualBlock?"blockwise":""})}},joinLines:function(e,t,n){var i,o;if(n.visualMode){if(i=e.getCursor("anchor"),ne(o=e.getCursor("head"),i)){var a=o;o=i,i=a}o.ch=ae(e,o.line)-1}else{var l=Math.max(t.repeat,2);i=e.getCursor(),o=X(e,r(i.line+l-1,1/0))}for(var s=0,c=i.line;c1)var a=Array(t.repeat+1).join(a);var p,m,g=o.linewise,v=o.blockwise;if(g)n.visualMode?a=n.visualLine?a.slice(0,-1):"\n"+a.slice(0,a.length-1)+"\n":t.after?(a="\n"+a.slice(0,a.length-1),i.ch=ae(e,i.line)):i.ch=0;else{if(v){a=a.split("\n");for(var y=0;ye.lastLine()&&e.replaceRange("\n",r(M,0));var T=ae(e,M);Tu.length&&(o=u.length),a=r(s.line,o)}if("\n"==l)i.visualMode||t.replaceRange("",s,a),(e.commands.newlineAndIndentContinueComment||e.commands.newlineAndIndent)(t);else{var f=t.getRange(s,a);if(f=f.replace(/[^\n]/g,l),i.visualBlock){var d=new Array(t.getOption("tabSize")+1).join(" ");f=(f=t.getSelection()).replace(/\t/g,d).replace(/[^\n]/g,l).split("\n"),t.replaceSelections(f)}else t.replaceRange(f,s,a);i.visualMode?(s=ne(c[0].anchor,c[0].head)?c[0].anchor:c[0].head,t.setCursor(s),pe(t,!1)):t.setCursor(J(a,0,-1))}},incrementNumberToken:function(e,t){for(var n,i,o,a,l=e.getCursor(),s=e.getLine(l.line),c=/(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi;null!==(n=c.exec(s))&&(i=n.index,o=i+n[0].length,!(l.ch"==t.slice(-11)){var n=t.length-11,r=e.slice(0,n),i=t.slice(0,n);return r==i&&e.length>n?"full":0==i.indexOf(r)&&"partial"}return e==t?"full":0==t.indexOf(e)&&"partial"}function Z(e,t,n){return function(){for(var r=0;r2&&(t=re.apply(void 0,Array.prototype.slice.call(arguments,1))),ne(e,t)?e:t}function ie(e,t){return arguments.length>2&&(t=ie.apply(void 0,Array.prototype.slice.call(arguments,1))),ne(e,t)?t:e}function oe(e,t,n){var r=ne(e,t),i=ne(t,n);return r&&i}function ae(e,t){return e.getLine(t).length}function le(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function se(e,t,n){var i=ae(e,t),o=new Array(n-i+1).join(" ");e.setCursor(r(t,i)),e.replaceRange(o,e.getCursor())}function ce(e,t){var n=[],i=e.listSelections(),o=ee(e.clipPos(t)),a=!te(t,o),l=e.getCursor("head"),s=function(e,t,n){for(var r=0;rs?u:0,d=i[f].anchor,h=Math.min(d.line,o.line),p=Math.max(d.line,o.line),m=d.ch,g=o.ch,v=i[f].head.ch-m,y=g-m;v>0&&y<=0?(m++,a||g--):v<0&&y>=0?(m--,c||g++):v<0&&-1==y&&(m--,g++);for(var b=h;b<=p;b++){var x={anchor:new r(b,m),head:new r(b,g)};n.push(x)}return e.setSelections(n),t.ch=g,d.ch=m,d}function ue(e,t,n){for(var r=[],i=0;ic&&(o.line=c),o.ch=ae(e,o.line)}return{ranges:[{anchor:a,head:o}],primary:0}}if("block"==n){for(var u=Math.min(a.line,o.line),f=Math.min(a.ch,o.ch),d=Math.max(a.line,o.line),h=Math.max(a.ch,o.ch)+1,p=d-u+1,m=o.line==u?0:p-1,g=[],v=0;v=l.length)return null;i?c=p[0]:(c=h[0])(l.charAt(s))||(c=h[1]);for(var u=s,f=s;c(l.charAt(u))&&u=0;)f--;if(f++,t){for(var d=u;/\s/.test(l.charAt(u))&&u0;)f--;f||(f=m)}}return{start:r(a.line,f),end:r(a.line,u)}}function ve(e,t,n){te(t,n)||E.jumpList.add(e,t,n)}function ye(e,t){E.lastCharacterSearch.increment=e,E.lastCharacterSearch.forward=t.forward,E.lastCharacterSearch.selectedCharacter=t.selectedCharacter}var be={"(":"bracket",")":"bracket","{":"bracket","}":"bracket","[":"section","]":"section","*":"comment","/":"comment",m:"method",M:"method","#":"preprocess"},xe={bracket:{isComplete:function(e){if(e.nextCh===e.symb){if(e.depth++,e.depth>=1)return!0}else e.nextCh===e.reverseSymb&&e.depth--;return!1}},section:{init:function(e){e.curMoveThrough=!0,e.symb=(e.forward?"]":"[")===e.symb?"{":"}"},isComplete:function(e){return 0===e.index&&e.nextCh===e.symb}},comment:{isComplete:function(e){var t="*"===e.lastCh&&"/"===e.nextCh;return e.lastCh=e.nextCh,t}},method:{init:function(e){e.symb="m"===e.symb?"{":"}",e.reverseSymb="{"===e.symb?"}":"{"},isComplete:function(e){return e.nextCh===e.symb}},preprocess:{init:function(e){e.index=0},isComplete:function(e){if("#"===e.nextCh){var t=e.lineText.match(/#(\w+)/)[1];if("endif"===t){if(e.forward&&0===e.depth)return!0;e.depth++}else if("if"===t){if(!e.forward&&0===e.depth)return!0;e.depth--}if("else"===t&&0===e.depth)return!0}return!1}}};function we(e,t,n,r,i){var o=t.line,a=t.ch,l=e.getLine(o),s=n?1:-1,c=r?p:h;if(i&&""==l){if(o+=s,l=e.getLine(o),!w(e,o))return null;a=n?0:l.length}for(;;){if(i&&""==l)return{from:0,to:0,line:o};for(var u=s>0?l.length:-1,f=u,d=u;a!=u;){for(var m=!1,g=0;g0?0:l.length}}function ke(e,t,n,i){for(var o,a=e.getCursor(),l=a.ch,s=0;s0;)d(u,i)&&n--,u+=i;return new r(u,0)}var h=e.state.vim;if(h.visualLine&&d(l,1,!0)){var p=h.sel.anchor;d(p.line,-1,!0)&&(o&&p.line==l||(l+=1))}var m=f(l);for(u=l;u<=c&&n;u++)d(u,1,!0)&&(o&&f(u)==m||n--);for(a=new r(u,0),u>c&&!m?m=!0:o=!1,u=l;u>s&&(o&&f(u)!=m&&u!=l||!d(u,-1,!0));u--);return{start:new r(u,0),end:a}}function Me(){}function Te(e){var t=e.state.vim;return t.searchState_||(t.searchState_=new Me)}function Ae(e,t,n,r,i){e.openDialog?e.openDialog(t,r,{bottom:!0,value:i.value,onKeyDown:i.onKeyDown,onKeyUp:i.onKeyUp,selectValueOnOpen:!1}):r(prompt(n,""))}function Oe(e,t){var n=Ne(e,t)||[];if(!n.length)return[];var r=[];if(0===n[0]){for(var i=0;i'+t+"",{bottom:!0,duration:5e3}):alert(t)}var Be="(Javascript regexp)";function De(e,t){var n,r,i,o=(t.prefix||"")+" "+(t.desc||""),a=(n=t.prefix,r=t.desc,i=''+(n||"")+'',r&&(i+=' '+r+""),i);Ae(e,a,o,t.onClose,t)}function Fe(e,t,n,r){if(t){var i=Te(e),o=Ie(t,!!n,!!r);if(o)return We(e,o),function(e,t){if(e instanceof RegExp&&t instanceof RegExp){for(var n=["global","multiline","ignoreCase","source"],r=0;r0;t--){var n=e.substring(0,t);if(this.commandMap_[n]){var r=this.commandMap_[n];if(0===r.name.indexOf(e))return r}}return null},buildCommandMap_:function(){this.commandMap_={};for(var e=0;e
";if(n){n=n.join("");for(var o=0;o"}}else for(var l in r){var s=r[l].toString();s.length&&(i+='"'+l+" "+s+"
")}Re(e,i)},sort:function(t,n){var i,o,a,l,s,c=function(){if(n.argString){var t=new e.StringStream(n.argString);if(t.eat("!")&&(i=!0),t.eol())return;if(!t.eatSpace())return"Invalid arguments";var r=t.match(/([dinuox]+)?\s*(\/.+\/)?\s*/);if(!r&&!t.eol())return"Invalid arguments";if(r[1]){o=-1!=r[1].indexOf("i"),a=-1!=r[1].indexOf("u");var c=-1!=r[1].indexOf("d")||-1!=r[1].indexOf("n")&&1,u=-1!=r[1].indexOf("x")&&1,f=-1!=r[1].indexOf("o")&&1;if(c+u+f>1)return"Invalid arguments";l=(c?"decimal":u&&"hex")||f&&"octal"}r[2]&&(s=new RegExp(r[2].substr(1,r[2].length-2),o?"i":""))}}();if(c)Re(t,c+": "+n.argString);else{var u=n.line||t.firstLine(),f=n.lineEnd||n.line||t.lastLine();if(u!=f){var d=r(u,0),h=r(f,ae(t,f)),p=t.getRange(d,h).split("\n"),m=s||("decimal"==l?/(-?)([\d]+)/:"hex"==l?/(-?)(?:0x)?([0-9a-f]+)/i:"octal"==l?/([0-7]+)/:null),g="decimal"==l?10:"hex"==l?16:"octal"==l?8:null,v=[],y=[];if(l||s)for(var b=0;b")}if(r){var h=0,p=function(){if(h=n&&e<=l:e==n);)if(r||!f||a.from().line!=f.line)return t.scrollIntoView(a.from(),30),t.setSelection(a.from(),a.to()),f=a.from(),void(u=!1);var e,n,l;u=!0}function m(e){if(e&&e(),t.focus(),f){t.setCursor(f);var n=t.state.vim;n.exMode=!1,n.lastHPos=n.lastHSPos=f.ch}c&&c()}if(p(),!u)return n?void De(t,{prefix:"replace with "+s+" (y/n/a/q/l)",onKeyDown:function(n,r,i){switch(e.e_stop(n),e.keyName(n)){case"Y":h(),p();break;case"N":p();break;case"A":var o=c;c=void 0,t.operation(d),c=o;break;case"L":h();case"Q":case"Esc":case"Ctrl-C":case"Ctrl-[":m(i)}return u&&m(i),!0}}):(d(),void(c&&c()));Re(t,"No matches for "+l.source)}(t,f,h,g,v,b,m,u,n.callback)}else Re(t,"No previous substitute regular expression")},redo:e.commands.redo,undo:e.commands.undo,write:function(t){e.commands.save?e.commands.save(t):t.save&&t.save()},nohlsearch:function(e){_e(e)},yank:function(e){var t=ee(e.getCursor()),n=t.line,r=e.getLine(n);E.registerController.pushText("0","yank",r,!0,!0)},delmarks:function(t,n){if(n.argString&&le(n.argString))for(var r=t.state.vim,i=new e.StringStream(le(n.argString));!i.eol();){i.eatSpace();var o=i.pos;if(!i.match(/[a-zA-Z]/,!1))return void Re(t,"Invalid argument: "+n.argString.substring(o));var a=i.next();if(i.match("-",!0)){if(!i.match(/[a-zA-Z]/,!1))return void Re(t,"Invalid argument: "+n.argString.substring(o));var l=a,s=i.next();if(!(k(l)&&k(s)||C(l)&&C(s)))return void Re(t,"Invalid argument: "+l+"-");var c=l.charCodeAt(0),u=s.charCodeAt(0);if(c>=u)return void Re(t,"Invalid argument: "+n.argString.substring(o));for(var f=0;f<=u-c;f++){var d=String.fromCharCode(c+f);delete r.marks[d]}}else delete r.marks[a]}else Re(t,"Argument required")}},Ve=new je;function qe(t){var n=t.state.vim,r=E.macroModeState,i=E.registerController.getRegister("."),o=r.isPlaying,a=r.lastInsertModeChanges,l=[];if(!o){for(var s=a.inVisualBlock&&n.lastSelection?n.lastSelection.visualBlock.height:1,c=a.changes,l=[],u=0;u1&&(et(t,n,n.insertModeRepeat-1,!0),n.lastEditInputState.repeatOverride=n.insertModeRepeat),delete n.insertModeRepeat,n.insertMode=!1,t.setCursor(t.getCursor().line,t.getCursor().ch-1),t.setOption("keyMap","vim"),t.setOption("disableInput",!0),t.toggleOverwrite(!1),i.setText(a.changes.join("")),e.signal(t,"vim-mode-change",{mode:"normal"}),r.isRecording&&function(e){if(!e.isPlaying){var t=e.latestRegister,n=E.registerController.getRegister(t);n&&n.pushInsertModeChanges&&n.pushInsertModeChanges(e.lastInsertModeChanges)}}(r)}function $e(e){t.unshift(e)}function Ge(t,n,r,i){var o=E.registerController.getRegister(i);if(":"==i)return o.keyBuffer[0]&&Ve.processCommand(t,o.keyBuffer[0]),void(r.isPlaying=!1);var a=o.keyBuffer,l=0;r.isPlaying=!0,r.replaySearchQueries=o.searchQueries.slice(0);for(var s=0;s|<\w+>|./.exec(f),u=c[0],f=f.substring(c.index+u.length),e.Vim.handleKey(t,u,"macro"),n.insertMode){var d=o.insertModeChanges[l++].changes;E.macroModeState.lastInsertModeChanges.changes=d,tt(t,d,1),qe(t)}r.isPlaying=!1}function Xe(e,t){var n=E.macroModeState,r=n.lastInsertModeChanges;if(!n.isPlaying)for(;t;){if(r.expectCursorActivityForChange=!0,"+input"==t.origin||"paste"==t.origin||void 0===t.origin){var i=t.text.join("\n");r.maybeReset&&(r.changes=[],r.maybeReset=!1),e.state.overwrite&&!/\n/.test(i)?r.changes.push([i]):r.changes.push(i)}t=t.next}}function Ye(t){var n=t.state.vim;if(n.insertMode){var r=E.macroModeState;if(r.isPlaying)return;var i=r.lastInsertModeChanges;i.expectCursorActivityForChange?i.expectCursorActivityForChange=!1:i.maybeReset=!0}else t.curOp.isVimOp||function(t,n){var r=t.getCursor("anchor"),i=t.getCursor("head");if(n.visualMode&&!t.somethingSelected()?pe(t,!1):n.visualMode||n.insertMode||!t.somethingSelected()||(n.visualMode=!0,n.visualLine=!1,e.signal(t,"vim-mode-change",{mode:"visual"})),n.visualMode){var o=ne(i,r)?0:-1,a=ne(i,r)?-1:0;i=J(i,0,o),r=J(r,0,a),n.sel={anchor:r,head:i},Ce(t,n,"<",re(i,r)),Ce(t,n,">",ie(i,r))}else n.insertMode||(n.lastHPos=t.getCursor().ch)}(t,n);n.visualMode&&Je(t)}function Je(e){var t=e.state.vim,n=X(e,ee(t.sel.head)),r=J(n,0,1);t.fakeCursor&&t.fakeCursor.clear(),t.fakeCursor=e.markText(n,r,{className:"cm-animate-fat-cursor"})}function Qe(e){this.keyName=e}function Ze(t){var n=E.macroModeState,r=n.lastInsertModeChanges,i=e.keyName(t);i&&(-1==i.indexOf("Delete")&&-1==i.indexOf("Backspace")||e.lookupKey(i,"vim-insert",function(){return r.maybeReset&&(r.changes=[],r.maybeReset=!1),r.changes.push(new Qe(i)),!0}))}function et(e,t,n,r){var i=E.macroModeState;i.isPlaying=!0;var o=!!t.lastEditActionCommand,a=t.inputState;function l(){o?U.processAction(e,t,t.lastEditActionCommand):U.evalInput(e,t)}function s(n){if(i.lastInsertModeChanges.changes.length>0){n=t.lastEditActionCommand?n:1;var r=i.lastInsertModeChanges;tt(e,r.changes,n)}}if(t.inputState=t.lastEditInputState,o&&t.lastEditActionCommand.interlaceInsertRepeat)for(var c=0;c50&&r.shift()}function o(e){return r[r.length-(e?Math.min(e,1):1)]||""}var a=null;function l(e,t,o,l,s){null==s&&(s=e.getRange(t,o)),"grow"==l&&a&&a.cm==e&&n(t,a.pos)&&e.isClean(a.gen)?function(e){if(!r.length)return i(e);r[r.length-1]+=e}(s):!1!==l&&i(s),e.replaceRange("",t,o,"+delete"),a="grow"==l?{cm:e,pos:t,gen:e.changeGeneration()}:null}function s(e,t,n){return e.findPosH(t,n,"char",!0)}function c(e,t,n){return e.findPosH(t,n,"word",!0)}function u(e,t,n){return e.findPosV(t,n,"line",e.doc.sel.goalColumn)}function f(e,t,n){return e.findPosV(t,n,"page",e.doc.sel.goalColumn)}function d(e,n,r){for(var i=n.line,o=e.getLine(i),a=/\S/.test(r<0?o.slice(0,n.ch):o.slice(n.ch)),l=e.firstLine(),s=e.lastLine();;){if((i+=r)s)return e.clipPos(t(i-r,r<0?0:null));o=e.getLine(i);var c=/\S/.test(o);if(c)a=!0;else if(a)return t(i,0)}}function h(e,n,r){for(var i=n.line,o=n.ch,a=e.getLine(n.line),l=!1;;){var s=a.charAt(o+(r<0?-1:0));if(s){if(l&&/[!?.]/.test(s))return t(i,o+(r>0?1:0));l||(l=/\w/.test(s)),o+=r}else{if(i==(r<0?e.firstLine():e.lastLine()))return t(i,o);if(a=e.getLine(i+r),!/\S/.test(a))return t(i,o);i+=r,o=r<0?a.length:0}}}function p(e,r,i){var o;if(e.findMatchingBracket&&(o=e.findMatchingBracket(r,{strict:!0}))&&o.match&&(o.forward?1:-1)==i)return i>0?t(o.to.line,o.to.ch+1):o.to;for(var a=!0;;a=!1){var l=e.getTokenAt(r),s=t(r.line,i<0?l.start:l.end);if(!(a&&i>0&&l.end==r.ch)&&/\w/.test(l.string))return s;var c=e.findPosH(s,i,"char");if(n(s,c))return r;r=c}}function m(e,t){var n=e.state.emacsPrefix;return n?(S(e),"-"==n?-1:Number(n)):t?null:1}function g(e){var t="string"==typeof e?function(t){t.execCommand(e)}:e;return function(e){var n=m(e);t(e);for(var r=1;r1&&"+input"==t.origin){for(var r=t.text.join("\n"),i="",o=1;o1&&r.pop(),o()),"around","paste")},"Ctrl-Space":T,"Ctrl-Shift-2":T,"Ctrl-F":y(s,1),"Ctrl-B":y(s,-1),Right:y(s,1),Left:y(s,-1),"Ctrl-D":function(e){b(e,s,1,!1)},Delete:function(e){x(e,!1)||b(e,s,1,!1)},"Ctrl-H":function(e){b(e,s,-1,!1)},Backspace:function(e){x(e,!1)||b(e,s,-1,!1)},"Alt-F":y(c,1),"Alt-B":y(c,-1),"Alt-Right":y(c,1),"Alt-Left":y(c,-1),"Alt-D":function(e){b(e,c,1,"grow")},"Alt-Backspace":function(e){b(e,c,-1,"grow")},"Ctrl-N":y(u,1),"Ctrl-P":y(u,-1),Down:y(u,1),Up:y(u,-1),"Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd",End:"goLineEnd",Home:"goLineStart","Alt-V":y(f,-1),"Ctrl-V":y(f,1),PageUp:y(f,-1),PageDown:y(f,1),"Ctrl-Up":y(d,-1),"Ctrl-Down":y(d,1),"Alt-A":y(h,-1),"Alt-E":y(h,1),"Alt-K":function(e){b(e,h,1,"grow")},"Ctrl-Alt-K":function(e){b(e,p,1,"grow")},"Ctrl-Alt-Backspace":function(e){b(e,p,-1,"grow")},"Ctrl-Alt-F":y(p,1),"Ctrl-Alt-B":y(p,-1),"Shift-Ctrl-Alt-2":function(e){var t=e.getCursor();e.setSelection(v(e,t,p,1),t)},"Ctrl-Alt-T":function(e){var t=p(e,e.getCursor(),-1),n=p(e,t,1),r=p(e,n,1),i=p(e,r,-1);e.replaceRange(e.getRange(i,r)+e.getRange(n,i)+e.getRange(t,n),t,r)},"Ctrl-Alt-U":g(function(e){for(var n=e.getCursor(),r=n.line,i=n.ch,o=[];r>=e.firstLine();){for(var a=e.getLine(r),l=null==i?a.length:i;l>0;){var i=a.charAt(--l);if(")"==i)o.push("(");else if("]"==i)o.push("[");else if("}"==i)o.push("{");else if(/[\(\{\[]/.test(i)&&(!o.length||o.pop()!=i))return e.extendSelection(t(r,l))}--r,i=null}}),"Alt-Space":function(e){for(var n=e.getCursor(),r=n.ch,i=n.ch,o=e.getLine(n.line);r&&/\s/.test(o.charAt(r-1));)--r;for(;i0)return e.setCursor(t-1);!function(e,t,n){e.openDialog?e.openDialog(t+': ',n,{bottom:!0}):n(prompt(t,""))}(e,"Goto line",function(t){var n;t&&!isNaN(n=Number(t))&&n==(0|n)&&n>0&&e.setCursor(n-1)})},"Ctrl-X Tab":function(e){e.indentSelection(m(e,!0)||e.getOption("indentUnit"))},"Ctrl-X Ctrl-X":function(e){e.setSelection(e.getCursor("head"),e.getCursor("anchor"))},"Ctrl-X Ctrl-S":"save","Ctrl-X Ctrl-W":"save","Ctrl-X S":"saveAll","Ctrl-X F":"open","Ctrl-X U":g("undo"),"Ctrl-X K":"close","Ctrl-X Delete":function(e){l(e,e.getCursor(),h(e,e.getCursor(),1),"grow")},"Ctrl-X H":"selectAll","Ctrl-Q Tab":g("insertTab"),"Ctrl-U":function(e){e.state.emacsPrefixMap=!0,e.addKeyMap(E),e.on("keyHandled",M),e.on("inputRead",M)}}),E={"Ctrl-G":S};function P(e){E[e]=function(t){w(t,e)},N["Ctrl-"+e]=function(t){w(t,e)},k["Ctrl-"+e]=!0}for(var I=0;I<10;++I)P(String(I));P("-")}(n(0))},function(e,t,n){var r;(r=n(0)).defineOption("showTrailingSpace",!1,function(e,t,n){n==r.Init&&(n=!1),n&&!t?e.removeOverlay("trailingspace"):!n&&t&&e.addOverlay({token:function(e){for(var t=e.string.length,n=t;n&&/\s/.test(e.string.charAt(n-1));--n);return n>e.pos?(e.pos=n,null):(e.pos=t,"trailingspace")},name:"trailingspace"})})},function(e,t,n){!function(e){"use strict";var t="CodeMirror-activeline",n="CodeMirror-activeline-background",r="CodeMirror-activeline-gutter";function i(e){for(var i=0;i>u",">>s",">=","<=","==","!=","=s",">=u",">s",">u","<",">","=","&","|","^","!"]);function l(e,t){var n;for(t.commentDepth=1;null!=(n=e.next());){if("*"===n&&e.eat("/")&&0==--t.commentDepth)return t.tokenize=null,"comment";"/"===n&&e.eat("*")&&t.commentDepth++}return"comment"}function s(e,t){for(var n,r=t.commentState;null!=(n=e.next());)if(0===r&&"t"===n)r=1;else if(1===r&&":"===n)return t.tokenize=null,t.commentState=0,r=2,"comment";return t.commentState=r,"comment"}return{startState:function(){return{tokenize:null,commentState:0,commentDepth:0}},token:function(n,c){if(n.eatSpace())return null;var u=(c.tokenize||function(n,c){var u,f=n.next();if("$"===f)return n.eatWhile(t),"variable";if("@"===f)return n.eatWhile(t),"meta";if('"'===f)return c.tokenize=(u=f,function(e,t){for(var n,r=!1;null!=(n=e.next());){if(n==u&&!r)return t.tokenize=null,"string";r=!r&&"\\"===n}return"string"}),c.tokenize(n,c);if("/"==f){if(n.eat("*"))return c.tokenize=l,l(n,c);if(n.eat("/"))return n.skipToEnd(),"comment"}if(/\d/.test(f)||("-"===f||"+"===f)&&/\d/.test(n.peek()))return n.eatWhile(/[\w\._\-+]/),"number";if(/[\[\]\(\)\{\},:]/.test(f))return null;if(o.test(f))return"operator";n.eatWhile(t);var d=n.current();if(d in a)return"operator";if(d in e)return"keyword";if(d in i){if(!n.eat(":"))return"builtin";n.eatWhile(t),d=n.current()}return d in r?"builtin":"Temporary"===d?(c.tokenize=s,c.tokenize(n,c)):null})(n,c);return u}}}),e.registerHelper("wordChars","wasm",t),e.defineMIME("text/wasm","wasm")})?r.apply(t,i):r)||(e.exports=o)},function(e,t,n){!function(e){"use strict";function t(e,t,n,r,i,o){this.indented=e,this.column=t,this.type=n,this.info=r,this.align=i,this.prev=o}function n(e,n,r,i){var o=e.indented;return e.context&&"statement"==e.context.type&&"statement"!=r&&(o=e.context.indented),e.context=new t(o,n,r,i,null,e.context)}function r(e){var t=e.context.type;return")"!=t&&"]"!=t&&"}"!=t||(e.indented=e.context.indented),e.context=e.context.prev}function i(e,t,n){return"variable"==t.prevToken||"type"==t.prevToken||!!/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(e.string.slice(0,n))||!(!t.typeAtEndOfLine||e.column()!=e.indentation())||void 0}function o(e){for(;;){if(!e||"top"==e.type)return!0;if("}"==e.type&&"namespace"!=e.prev.info)return!1;e=e.prev}}function a(e){for(var t={},n=e.split(" "),r=0;r!?|\/]/,O=s.isIdentifierChar||/[\w\$_\xa1-\uffff]/;function N(e,t){var n,r=e.next();if(x[r]){var i=x[r](e,t);if(!1!==i)return i}if('"'==r||"'"==r)return t.tokenize=(n=r,function(e,t){for(var r,i=!1,o=!1;null!=(r=e.next());){if(r==n&&!i){o=!0;break}i=!i&&"\\"==r}return(o||!i&&!w)&&(t.tokenize=null),"string"}),t.tokenize(e,t);if(L.test(r))return c=r,null;if(M.test(r)){if(e.backUp(1),e.match(T))return"number";e.next()}if("/"==r){if(e.eat("*"))return t.tokenize=E,E(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(A.test(r)){for(;!e.match(/^\/[\/*]/,!1)&&e.eat(A););return"operator"}if(e.eatWhile(O),S)for(;e.match(S);)e.eatWhile(O);var o=e.current();return l(p,o)?(l(v,o)&&(c="newstatement"),l(y,o)&&(u=!0),"keyword"):l(m,o)?"type":l(g,o)?(l(v,o)&&(c="newstatement"),"builtin"):l(b,o)?"atom":"variable"}function E(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="*"==n}return"comment"}function P(e,t){s.typeFirstDefinitions&&e.eol()&&o(t.context)&&(t.typeAtEndOfLine=i(e,t,e.pos))}return{startState:function(e){return{tokenize:null,context:new t((e||0)-f,0,"top",null,!1),indented:0,startOfLine:!0,prevToken:null}},token:function(e,t){var a=t.context;if(e.sol()&&(null==a.align&&(a.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return P(e,t),null;c=u=null;var l=(t.tokenize||N)(e,t);if("comment"==l||"meta"==l)return l;if(null==a.align&&(a.align=!0),";"==c||":"==c||","==c&&e.match(/^\s*(?:\/\/.*)?$/,!1))for(;"statement"==t.context.type;)r(t);else if("{"==c)n(t,e.column(),"}");else if("["==c)n(t,e.column(),"]");else if("("==c)n(t,e.column(),")");else if("}"==c){for(;"statement"==a.type;)a=r(t);for("}"==a.type&&(a=r(t));"statement"==a.type;)a=r(t)}else c==a.type?r(t):k&&(("}"==a.type||"top"==a.type)&&";"!=c||"statement"==a.type&&"newstatement"==c)&&n(t,e.column(),"statement",e.current());if("variable"==l&&("def"==t.prevToken||s.typeFirstDefinitions&&i(e,t,e.start)&&o(t.context)&&e.match(/^\s*\(/,!1))&&(l="def"),x.token){var f=x.token(e,t,l);void 0!==f&&(l=f)}return"def"==l&&!1===s.styleDefs&&(l="variable"),t.startOfLine=!1,t.prevToken=u?"def":l||c,P(e,t),l},indent:function(t,n){if(t.tokenize!=N&&null!=t.tokenize||t.typeAtEndOfLine)return e.Pass;var r=t.context,i=n&&n.charAt(0);if("statement"==r.type&&"}"==i&&(r=r.prev),s.dontIndentStatements)for(;"statement"==r.type&&s.dontIndentStatements.test(r.info);)r=r.prev;if(x.indent){var o=x.indent(t,r,n);if("number"==typeof o)return o}var a=i==r.type,l=r.prev&&"switch"==r.prev.info;if(s.allmanIndentation&&/[{(]/.test(i)){for(;"top"!=r.type&&"}"!=r.type;)r=r.prev;return r.indented}return"statement"==r.type?r.indented+("{"==i?0:d):!r.align||h&&")"==r.type?")"!=r.type||a?r.indented+(a?0:f)+(a||!l||/^(?:case|default)\b/.test(n)?0:f):r.indented+d:r.column+(a?0:1)},electricInput:C?/^\s*(?:case .*?:|default:|\{\}?|\})$/:/^\s*[{}]$/,blockCommentStart:"/*",blockCommentEnd:"*/",blockCommentContinue:" * ",lineComment:"//",fold:"brace"}});var s="auto if break case register continue return default do sizeof static else struct switch extern typedef union for goto while enum const volatile",c="int long char short double float unsigned signed void size_t ptrdiff_t";function u(e,t){if(!t.startOfLine)return!1;for(var n,r=null;n=e.peek();){if("\\"==n&&e.match(/^.$/)){r=u;break}if("/"==n&&e.match(/^\/[\/\*]/,!1))break;e.next()}return t.tokenize=r,"meta"}function f(e,t){return"type"==t.prevToken&&"type"}function d(e){return e.eatWhile(/[\w\.']/),"number"}function h(e,t){if(e.backUp(1),e.match(/(R|u8R|uR|UR|LR)/)){var n=e.match(/"([^\s\\()]{0,16})\(/);return!!n&&(t.cpp11RawStringDelim=n[1],t.tokenize=m,m(e,t))}return e.match(/(u8|u|U|L)/)?!!e.match(/["']/,!1)&&"string":(e.next(),!1)}function p(e,t){for(var n;null!=(n=e.next());)if('"'==n&&!e.eat('"')){t.tokenize=null;break}return"string"}function m(e,t){var n=t.cpp11RawStringDelim.replace(/[^\w\s]/g,"\\$&"),r=e.match(new RegExp(".*?\\)"+n+'"'));return r?t.tokenize=null:e.skipToEnd(),"string"}function g(t,n){"string"==typeof t&&(t=[t]);var r=[];function i(e){if(e)for(var t in e)e.hasOwnProperty(t)&&r.push(t)}i(n.keywords),i(n.types),i(n.builtin),i(n.atoms),r.length&&(n.helperType=t[0],e.registerHelper("hintWords",t[0],r));for(var o=0;o!?|\/#:@]/,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return!!e.match('""')&&(t.tokenize=v,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},"=":function(e,n){var r=n.context;return!("}"!=r.type||!r.align||!e.eat(">"))&&(n.context=new t(r.indented,r.column,r.type,r.info,null,r.prev),"operator")},"/":function(e,t){return!!e.eat("*")&&(t.tokenize=function e(t){return function(n,r){for(var i;i=n.next();){if("*"==i&&n.eat("/")){if(1==t){r.tokenize=null;break}return r.tokenize=e(t-1),r.tokenize(n,r)}if("/"==i&&n.eat("*"))return r.tokenize=e(t+1),r.tokenize(n,r)}return"comment"}}(1),t.tokenize(e,t))}},modeProps:{closeBrackets:{triples:'"'}}}),g("text/x-kotlin",{name:"clike",keywords:a("package as typealias class interface this super val operator var fun for is in This throw return annotation break continue object if else while do try when !in !is as? file import where by get set abstract enum open inner override private public internal protected catch finally out final vararg reified dynamic companion constructor init sealed field property receiver param sparam lateinit data inline noinline tailrec external annotation crossinline const operator infix suspend actual expect setparam"),types:a("Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable Compiler Double Exception Float Integer Long Math Number Object Package Pair Process Runtime Runnable SecurityManager Short StackTraceElement StrictMath String StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy LazyThreadSafetyMode LongArray Nothing ShortArray Unit"),intendSwitch:!1,indentStatements:!1,multiLineStrings:!0,number:/^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i,blockKeywords:a("catch class do else finally for if where try while enum"),defKeywords:a("class val var object interface fun"),atoms:a("true false null this"),hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){var n;return t.tokenize=(n=e.match('""'),function(e,t){for(var r,i=!1,o=!1;!e.eol();){if(!n&&!i&&e.match('"')){o=!0;break}if(n&&e.match('"""')){o=!0;break}r=e.next(),!i&&"$"==r&&e.match("{")&&e.skipTo("}"),i=!i&&"\\"==r&&!n}return!o&&n||(t.tokenize=null),"string"}),t.tokenize(e,t)}},modeProps:{closeBrackets:{triples:'"'}}}),g(["x-shader/x-vertex","x-shader/x-fragment"],{name:"clike",keywords:a("sampler1D sampler2D sampler3D samplerCube sampler1DShadow sampler2DShadow const attribute uniform varying break continue discard return for while do if else struct in out inout"),types:a("float int bool void vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 mat2 mat3 mat4"),blockKeywords:a("for while do if else struct"),builtin:a("radians degrees sin cos tan asin acos atan pow exp log exp2 sqrt inversesqrt abs sign floor ceil fract mod min max clamp mix step smoothstep length distance dot cross normalize ftransform faceforward reflect refract matrixCompMult lessThan lessThanEqual greaterThan greaterThanEqual equal notEqual any all not texture1D texture1DProj texture1DLod texture1DProjLod texture2D texture2DProj texture2DLod texture2DProjLod texture3D texture3DProj texture3DLod texture3DProjLod textureCube textureCubeLod shadow1D shadow2D shadow1DProj shadow2DProj shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod dFdx dFdy fwidth noise1 noise2 noise3 noise4"),atoms:a("true false gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_FogCoord gl_PointCoord gl_Position gl_PointSize gl_ClipVertex gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor gl_TexCoord gl_FogFragCoord gl_FragCoord gl_FrontFacing gl_FragData gl_FragDepth gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose gl_ProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixInverseTranspose gl_TextureMatrixInverseTranspose gl_NormalScale gl_DepthRange gl_ClipPlane gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel gl_FrontLightModelProduct gl_BackLightModelProduct gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ gl_FogParameters gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits gl_MaxDrawBuffers"),indentSwitch:!1,hooks:{"#":u},modeProps:{fold:["brace","include"]}}),g("text/x-nesc",{name:"clike",keywords:a(s+"as atomic async call command component components configuration event generic implementation includes interface module new norace nx_struct nx_union post provides signal task uses abstract extends"),types:a(c),blockKeywords:a("case do else for if switch while struct"),atoms:a("null true false"),hooks:{"#":u},modeProps:{fold:["brace","include"]}}),g("text/x-objectivec",{name:"clike",keywords:a(s+"inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"),types:a(c),atoms:a("YES NO NULL NILL ON OFF true false"),hooks:{"@":function(e){return e.eatWhile(/[\w\$]/),"keyword"},"#":u,indent:function(e,t,n){if("statement"==t.type&&/^@\w/.test(n))return t.indented}},modeProps:{fold:"brace"}}),g("text/x-squirrel",{name:"clike",keywords:a("base break clone continue const default delete enum extends function in class foreach local resume return this throw typeof yield constructor instanceof static"),types:a(c),blockKeywords:a("case catch class else for foreach if switch try while"),defKeywords:a("function local class"),typeFirstDefinitions:!0,atoms:a("true false null"),hooks:{"#":u},modeProps:{fold:["brace","include"]}});var y=null;g("text/x-ceylon",{name:"clike",keywords:a("abstracts alias assembly assert assign break case catch class continue dynamic else exists extends finally for function given if import in interface is let module new nonempty object of out outer package return satisfies super switch then this throw try value void while"),types:function(e){var t=e.charAt(0);return t===t.toUpperCase()&&t!==t.toLowerCase()},blockKeywords:a("case catch class dynamic else finally for function if interface module new object switch try while"),defKeywords:a("class dynamic function interface module object package value"),builtin:a("abstract actual aliased annotation by default deprecated doc final formal late license native optional sealed see serializable shared suppressWarnings tagged throws variable"),isPunctuationChar:/[\[\]{}\(\),;\:\.`]/,isOperatorChar:/[+\-*&%=<>!?|^~:\/]/,numberStart:/[\d#$]/,number:/^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,multiLineStrings:!0,typeFirstDefinitions:!0,atoms:a("true false null larger smaller equal empty finished"),indentSwitch:!1,styleDefs:!1,hooks:{"@":function(e){return e.eatWhile(/[\w\$_]/),"meta"},'"':function(e,t){return t.tokenize=function e(t){return function(n,r){for(var i,o=!1,a=!1;!n.eol();){if(!o&&n.match('"')&&("single"==t||n.match('""'))){a=!0;break}if(!o&&n.match("``")){y=e(t),a=!0;break}i=n.next(),o="single"==t&&!o&&"\\"==i}return a&&(r.tokenize=null),"string"}}(e.match('""')?"triple":"single"),t.tokenize(e,t)},"`":function(e,t){return!(!y||!e.match("`"))&&(t.tokenize=y,y=null,t.tokenize(e,t))},"'":function(e){return e.eatWhile(/[\w\$_\xa1-\uffff]/),"atom"},token:function(e,t,n){if(("variable"==n||"type"==n)&&"."==t.prevToken)return"variable-2"}},modeProps:{fold:["brace","import"],closeBrackets:{triples:'"'}}})}(n(0))},function(e,t,n){!function(e){"use strict";e.defineMode("elm",function(){function e(e,t,n){return t(n),n(e,t)}var t=/[a-z_]/,n=/[A-Z]/,r=/[0-9]/,i=/[0-9A-Fa-f]/,o=/[0-7]/,a=/[a-z_A-Z0-9\']/,l=/[-!#$%&*+.\/<=>?@\\^|~:\u03BB\u2192]/,s=/[(),;[\]`{}]/,c=/[ \t\v\f]/;function u(){return function(d,h){if(d.eatWhile(c))return null;var p=d.next();if(s.test(p)){if("{"==p&&d.eat("-")){var m="comment";return d.eat("#")&&(m="meta"),e(d,h,function e(t,n){return 0==n?u():function(r,i){for(var o=n;!r.eol();){var a=r.next();if("{"==a&&r.eat("-"))++o;else if("-"==a&&r.eat("}")&&0==--o)return i(u()),t}return i(e(t,o)),t}}(m,1))}return null}if("'"==p)return d.eat("\\"),d.next(),d.eat("'")?"string":"error";if('"'==p)return e(d,h,f);if(n.test(p))return d.eatWhile(a),d.eat(".")?"qualifier":"variable-2";if(t.test(p)){var g=1===d.pos;return d.eatWhile(a),g?"type":"variable"}if(r.test(p)){if("0"==p){if(d.eat(/[xX]/))return d.eatWhile(i),"integer";if(d.eat(/[oO]/))return d.eatWhile(o),"number"}d.eatWhile(r);var m="number";return d.eat(".")&&(m="number",d.eatWhile(r)),d.eat(/[eE]/)&&(m="number",d.eat(/[-+]/),d.eatWhile(r)),m}return l.test(p)?"-"==p&&d.eat(/-/)&&(d.eatWhile(/-/),!d.eat(l))?(d.skipToEnd(),"comment"):(d.eatWhile(l),"builtin"):"error"}}function f(e,t){for(;!e.eol();){var n=e.next();if('"'==n)return t(u()),"string";if("\\"==n){if(e.eol()||e.eat(c))return t(d),"string";e.eat("&")||e.next()}}return t(u()),"error"}function d(t,n){return t.eat("\\")?e(t,n,f):(t.next(),n(u()),"error")}var h=function(){for(var e={},t=["case","of","as","if","then","else","let","in","infix","infixl","infixr","type","alias","input","output","foreign","loopback","module","where","import","exposing","_","..","|",":","=","\\",'"',"->","<-"],n=t.length;n--;)e[t[n]]="keyword";return e}();return{startState:function(){return{f:u()}},copyState:function(e){return{f:e.f}},token:function(e,t){var n=t.f(e,function(e){t.f=e}),r=e.current();return h.hasOwnProperty(r)?h[r]:n}}}),e.defineMIME("text/x-elm","elm")}(n(0))},function(e,t,n){!function(e){"use strict";e.defineMode("coffeescript",function(e,t){var n="error";function r(e){return new RegExp("^(("+e.join(")|(")+"))\\b")}var i=/^(?:->|=>|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|<[><]?=?|>>?=?|%=?|&=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&&|\?)=)/,o=/^(?:[()\[\]{},:`=;]|\.\.?\.?)/,a=/^[_A-Za-z$][_A-Za-z$0-9]*/,l=/^@[_A-Za-z$][_A-Za-z$0-9]*/,s=r(["and","or","not","is","isnt","in","instanceof","typeof"]),c=["for","while","loop","if","unless","else","switch","try","catch","finally","class"],u=r(c.concat(["break","by","continue","debugger","delete","do","in","of","new","return","then","this","@","throw","when","until","extends"]));c=r(c);var f=/^('{3}|\"{3}|['\"])/,d=/^(\/{3}|\/)/,h=r(["Infinity","NaN","undefined","null","true","false","on","off","yes","no"]);function p(e,t){if(e.sol()){null===t.scope.align&&(t.scope.align=!1);var r=t.scope.offset;if(e.eatSpace()){var c=e.indentation();return c>r&&"coffee"==t.scope.type?"indent":c0&&y(e,t)}if(e.eatSpace())return null;var p=e.peek();if(e.match("####"))return e.skipToEnd(),"comment";if(e.match("###"))return t.tokenize=g,t.tokenize(e,t);if("#"===p)return e.skipToEnd(),"comment";if(e.match(/^-?[0-9\.]/,!1)){var v=!1;if(e.match(/^-?\d*\.\d+(e[\+\-]?\d+)?/i)&&(v=!0),e.match(/^-?\d+\.\d*/)&&(v=!0),e.match(/^-?\.\d+/)&&(v=!0),v)return"."==e.peek()&&e.backUp(1),"number";var b=!1;if(e.match(/^-?0x[0-9a-f]+/i)&&(b=!0),e.match(/^-?[1-9]\d*(e[\+\-]?\d+)?/)&&(b=!0),e.match(/^-?0(?![\dx])/i)&&(b=!0),b)return"number"}if(e.match(f))return t.tokenize=m(e.current(),!1,"string"),t.tokenize(e,t);if(e.match(d)){if("/"!=e.current()||e.match(/^.*\//,!1))return t.tokenize=m(e.current(),!0,"string-2"),t.tokenize(e,t);e.backUp(1)}return e.match(i)||e.match(s)?"operator":e.match(o)?"punctuation":e.match(h)?"atom":e.match(l)||t.prop&&e.match(a)?"property":e.match(u)?"keyword":e.match(a)?"variable":(e.next(),n)}function m(e,r,i){return function(o,a){for(;!o.eol();)if(o.eatWhile(/[^'"\/\\]/),o.eat("\\")){if(o.next(),r&&o.eol())return i}else{if(o.match(e))return a.tokenize=p,i;o.eat(/['"\/]/)}return r&&(t.singleLineStringErrors?i=n:a.tokenize=p),i}}function g(e,t){for(;!e.eol();){if(e.eatWhile(/[^#]/),e.match("###")){t.tokenize=p;break}e.eatWhile("#")}return"comment"}function v(t,n,r){r=r||"coffee";for(var i=0,o=!1,a=null,l=n.scope;l;l=l.prev)if("coffee"===l.type||"}"==l.type){i=l.offset+e.indentUnit;break}"coffee"!==r?(o=null,a=t.column()+t.current().length):n.scope.align&&(n.scope.align=!1),n.scope={offset:i,type:r,prev:n.scope,align:o,alignOffset:a}}function y(e,t){if(t.scope.prev){if("coffee"===t.scope.type){for(var n=e.indentation(),r=!1,i=t.scope;i;i=i.prev)if(n===i.offset){r=!0;break}if(!r)return!0;for(;t.scope.prev&&t.scope.offset!==n;)t.scope=t.scope.prev;return!1}return t.scope=t.scope.prev,!1}}var b={startState:function(e){return{tokenize:p,scope:{offset:e||0,type:"coffee",prev:null,align:!1},prop:!1,dedent:0}},token:function(e,t){var r=null===t.scope.align&&t.scope;r&&e.sol()&&(r.align=!1);var i=function(e,t){var r=t.tokenize(e,t),i=e.current();"return"===i&&(t.dedent=!0),(("->"===i||"=>"===i)&&e.eol()||"indent"===r)&&v(e,t);var o="[({".indexOf(i);if(-1!==o&&v(e,t,"])}".slice(o,o+1)),c.exec(i)&&v(e,t),"then"==i&&y(e,t),"dedent"===r&&y(e,t))return n;if(-1!==(o="])}".indexOf(i))){for(;"coffee"==t.scope.type&&t.scope.prev;)t.scope=t.scope.prev;t.scope.type==i&&(t.scope=t.scope.prev)}return t.dedent&&e.eol()&&("coffee"==t.scope.type&&t.scope.prev&&(t.scope=t.scope.prev),t.dedent=!1),r}(e,t);return i&&"comment"!=i&&(r&&(r.align=!0),t.prop="punctuation"==i&&"."==e.current()),i},indent:function(e,t){if(e.tokenize!=p)return 0;var n=e.scope,r=t&&"])}".indexOf(t.charAt(0))>-1;if(r)for(;"coffee"==n.type&&n.prev;)n=n.prev;var i=r&&n.type===t.charAt(0);return n.align?n.alignOffset-(i?1:0):(i?n.prev:n).offset},lineComment:"#",fold:"indent"};return b}),e.defineMIME("application/vnd.coffeescript","coffeescript"),e.defineMIME("text/x-coffeescript","coffeescript"),e.defineMIME("text/coffeescript","coffeescript")}(n(0))},function(e,t,n){!function(e){"use strict";function t(e,t,n,r){this.state=e,this.mode=t,this.depth=n,this.prev=r}e.defineMode("jsx",function(n,r){var i=e.getMode(n,{name:"xml",allowMissing:!0,multilineTagIndentPastTag:!1,allowMissingTagName:!0}),o=e.getMode(n,r&&r.base||"javascript");function a(e){var t=e.tagName;e.tagName=null;var n=i.indent(e,"");return e.tagName=t,n}function l(r,s){return s.context.mode==i?function(r,s,c){if(2==c.depth)return r.match(/^.*?\*\//)?c.depth=1:r.skipToEnd(),"comment";if("{"==r.peek()){i.skipAttribute(c.state);var u=a(c.state),f=c.state.context;if(f&&r.match(/^[^>]*>\s*$/,!1)){for(;f.prev&&!f.startOfLine;)f=f.prev;f.startOfLine?u-=n.indentUnit:c.prev.state.lexical&&(u=c.prev.state.lexical.indented)}else 1==c.depth&&(u+=n.indentUnit);return s.context=new t(e.startState(o,u),o,0,s.context),null}if(1==c.depth){if("<"==r.peek())return i.skipAttribute(c.state),s.context=new t(e.startState(i,a(c.state)),i,0,s.context),null;if(r.match("//"))return r.skipToEnd(),"comment";if(r.match("/*"))return c.depth=2,l(r,s)}var d,h=i.token(r,c.state),p=r.current();return/\btag\b/.test(h)?/>$/.test(p)?c.state.context?c.depth=0:s.context=s.context.prev:/^-1&&r.backUp(p.length-d),h}(r,s,s.context):function(n,r,a){if("<"==n.peek()&&o.expressionAllowed(n,a.state))return o.skipExpression(a.state),r.context=new t(e.startState(i,o.indent(a.state,"")),i,0,r.context),null;var l=o.token(n,a.state);if(!l&&null!=a.depth){var s=n.current();"{"==s?a.depth++:"}"==s&&0==--a.depth&&(r.context=r.context.prev)}return l}(r,s,s.context)}return{startState:function(){return{context:new t(e.startState(o),o)}},copyState:function(n){return{context:function n(r){return new t(e.copyState(r.mode,r.state),r.mode,r.depth,r.prev&&n(r.prev))}(n.context)}},token:l,indent:function(e,t,n){return e.context.mode.indent(e.context.state,t,n)},innerMode:function(e){return e.context}}},"xml","javascript"),e.defineMIME("text/jsx","jsx"),e.defineMIME("text/typescript-jsx",{name:"jsx",base:{name:"javascript",typescript:!0}})}(n(0),n(2),n(3))},function(e,t,n){!function(e){"use strict";var t={script:[["lang",/(javascript|babel)/i,"javascript"],["type",/^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i,"javascript"],["type",/./,"text/plain"],[null,null,"javascript"]],style:[["lang",/^css$/i,"css"],["type",/^(text\/)?(x-)?(stylesheet|css)$/i,"css"],["type",/./,"text/plain"],[null,null,"css"]]},n={};function r(e,t){var r=e.match(function(e){var t=n[e];return t||(n[e]=new RegExp("\\s+"+e+"\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"))}(t));return r?/^\s*(.*?)\s*$/.exec(r[2])[1]:""}function i(e,t){return new RegExp((t?"^":"")+"","i")}function o(e,t){for(var n in e)for(var r=t[n]||(t[n]=[]),i=e[n],o=i.length-1;o>=0;o--)r.unshift(i[o])}e.defineMode("htmlmixed",function(n,a){var l=e.getMode(n,{name:"xml",htmlMode:!0,multilineTagIndentFactor:a.multilineTagIndentFactor,multilineTagIndentPastTag:a.multilineTagIndentPastTag}),s={},c=a&&a.tags,u=a&&a.scriptTypes;if(o(t,s),c&&o(c,s),u)for(var f=u.length-1;f>=0;f--)s.script.unshift(["type",u[f].matches,u[f].mode]);function d(t,o){var a,c=l.token(t,o.htmlState),u=/\btag\b/.test(c);if(u&&!/[<>\s\/]/.test(t.current())&&(a=o.htmlState.tagName&&o.htmlState.tagName.toLowerCase())&&s.hasOwnProperty(a))o.inTag=a+" ";else if(o.inTag&&u&&/>$/.test(t.current())){var f=/^([\S]+) (.*)/.exec(o.inTag);o.inTag=null;var h=">"==t.current()&&function(e,t){for(var n=0;n-1?e.backUp(r.length-i):r.match(/<\/?$/)&&(e.backUp(r.length),e.match(t,!1)||e.match(r)),n}(e,g,t.localMode.token(e,t.localState))},o.localMode=p,o.localState=e.startState(p,l.indent(o.htmlState,""))}else o.inTag&&(o.inTag+=t.current(),t.eol()&&(o.inTag+=" "));return c}return{startState:function(){var t=e.startState(l);return{token:d,inTag:null,localMode:null,localState:null,htmlState:t}},copyState:function(t){var n;return t.localState&&(n=e.copyState(t.localMode,t.localState)),{token:t.token,inTag:t.inTag,localMode:t.localMode,localState:n,htmlState:e.copyState(l,t.htmlState)}},token:function(e,t){return t.token(e,t)},indent:function(t,n,r){return!t.localMode||/^\s*<\//.test(n)?l.indent(t.htmlState,n):t.localMode.indent?t.localMode.indent(t.localState,n,r):e.Pass},innerMode:function(e){return{state:e.localState||e.htmlState,mode:e.localMode||l}}}},"xml","javascript","css"),e.defineMIME("text/html","htmlmixed")}(n(0),n(2),n(3),n(7))},function(e,t,n){!function(e){"use strict";var t={},n=/[^\s\u00a0]/,r=e.Pos;function i(e){var t=e.search(n);return-1==t?0:t}function o(e,t){var n=e.getMode();return!1!==n.useInnerComments&&n.innerMode?e.getModeAt(t):n}e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",function(e){e||(e=t);for(var n=1/0,i=this.listSelections(),o=null,a=i.length-1;a>=0;a--){var l=i[a].from(),s=i[a].to();l.line>=n||(s.line>=n&&(s=r(n,0)),n=l.line,null==o?this.uncomment(l,s,e)?o="un":(this.lineComment(l,s,e),o="line"):"un"==o?this.uncomment(l,s,e):this.lineComment(l,s,e))}}),e.defineExtension("lineComment",function(e,a,l){l||(l=t);var s=this,c=o(s,e),u=s.getLine(e.line);if(null!=u&&(f=e,d=u,!/\bstring\b/.test(s.getTokenTypeAt(r(f.line,0)))||/^[\'\"\`]/.test(d))){var f,d,h=l.lineComment||c.lineComment;if(h){var p=Math.min(0!=a.ch||a.line==e.line?a.line+1:a.line,s.lastLine()+1),m=null==l.padding?" ":l.padding,g=l.commentBlankLines||e.line==a.line;s.operation(function(){if(l.indent){for(var t=null,o=e.line;oc.length)&&(t=c)}for(var o=e.line;of||l.operation(function(){if(0!=a.fullLines){var t=n.test(l.getLine(f));l.replaceRange(d+u,r(f)),l.replaceRange(c+d,r(e.line,0));var o=a.blockCommentLead||s.blockCommentLead;if(null!=o)for(var h=e.line+1;h<=f;++h)(h!=f||t)&&l.replaceRange(o+d,r(h,0))}else l.replaceRange(u,i),l.replaceRange(c,e)})}}else(a.lineComment||s.lineComment)&&0!=a.fullLines&&l.lineComment(e,i,a)}),e.defineExtension("uncomment",function(e,i,a){a||(a=t);var l,s=this,c=o(s,e),u=Math.min(0!=i.ch||i.line==e.line?i.line:i.line-1,s.lastLine()),f=Math.min(e.line,u),d=a.lineComment||c.lineComment,h=[],p=null==a.padding?" ":a.padding;e:if(d){for(var m=f;m<=u;++m){var g=s.getLine(m),v=g.indexOf(d);if(v>-1&&!/comment/.test(s.getTokenTypeAt(r(m,v+1)))&&(v=-1),-1==v&&n.test(g))break e;if(v>-1&&n.test(g.slice(0,v)))break e;h.push(g)}if(s.operation(function(){for(var e=f;e<=u;++e){var t=h[e-f],n=t.indexOf(d),i=n+d.length;n<0||(t.slice(i,i+p.length)==p&&(i+=p.length),l=!0,s.replaceRange("",r(e,n),r(e,i)))}}),l)return!0}var y=a.blockCommentStart||c.blockCommentStart,b=a.blockCommentEnd||c.blockCommentEnd;if(!y||!b)return!1;var x=a.blockCommentLead||c.blockCommentLead,w=s.getLine(f),k=w.indexOf(y);if(-1==k)return!1;var C=u==f?w:s.getLine(u),S=C.indexOf(b,u==f?k+y.length:0),L=r(f,k+1),M=r(u,S+1);if(-1==S||!/comment/.test(s.getTokenTypeAt(L))||!/comment/.test(s.getTokenTypeAt(M))||s.getRange(L,M,"\n").indexOf(b)>-1)return!1;var T=w.lastIndexOf(y,e.ch),A=-1==T?-1:w.slice(0,e.ch).indexOf(b,T+y.length);if(-1!=T&&-1!=A&&A+b.length!=e.ch)return!1;A=C.indexOf(b,i.ch);var O=C.slice(i.ch).lastIndexOf(y,A-i.ch);return T=-1==A||-1==O?-1:i.ch+O,(-1==A||-1==T||T==i.ch)&&(s.operation(function(){s.replaceRange("",r(u,S-(p&&C.slice(S-p.length,S)==p?p.length:0)),r(u,S+b.length));var e=k+y.length;if(p&&w.slice(e,e+p.length)==p&&(e+=p.length),s.replaceRange("",r(f,k),r(f,e)),x)for(var t=f+1;t<=u;++t){var i=s.getLine(t),o=i.indexOf(x);if(-1!=o&&!n.test(i.slice(0,o))){var a=o+x.length;p&&i.slice(a,a+p.length)==p&&(a+=p.length),s.replaceRange("",r(t,o),r(t,a))}}}),!0)})}(n(0))},function(e,t,n){!function(e){var t={pairs:"()[]{}''\"\"",triples:"",explode:"[]{}"},n=e.Pos;function r(e,n){return"pairs"==n&&"string"==typeof e?e:"object"==typeof e&&null!=e[n]?e[n]:t[n]}e.defineOption("autoCloseBrackets",!1,function(t,n,a){a&&a!=e.Init&&(t.removeKeyMap(i),t.state.closeBrackets=null),n&&(o(r(n,"pairs")),t.state.closeBrackets=n,t.addKeyMap(i))});var i={Backspace:function(t){var i=l(t);if(!i||t.getOption("disableInput"))return e.Pass;for(var o=r(i,"pairs"),a=t.listSelections(),s=0;s=0;s--){var f=a[s].head;t.replaceRange("",n(f.line,f.ch-1),n(f.line,f.ch+1),"+delete")}},Enter:function(t){var n=l(t),i=n&&r(n,"explode");if(!i||t.getOption("disableInput"))return e.Pass;for(var o=t.listSelections(),a=0;a1&&d.indexOf(i)>=0&&t.getRange(n(b.line,b.ch-2),b)==i+i){if(b.ch>2&&/\bstring/.test(t.getTokenTypeAt(n(b.line,b.ch-2))))return e.Pass;v="addFour"}else if(h){var w=0==b.ch?" ":t.getRange(n(b.line,b.ch-1),b);if(e.isWordChar(x)||w==i||e.isWordChar(w))return e.Pass;v="both"}else{if(!m||t.getLine(b.line).length!=b.ch&&!s(x,a)&&!/\s/.test(x))return e.Pass;v="both"}else v=h&&u(t,b)?"both":d.indexOf(i)>=0&&t.getRange(b,n(b.line,b.ch+3))==i+i+i?"skipThree":"skip";if(f){if(f!=v)return e.Pass}else f=v}var k=c%2?a.charAt(c-1):i,C=c%2?i:a.charAt(c+1);t.operation(function(){if("skip"==f)t.execCommand("goCharRight");else if("skipThree"==f)for(var r=0;r<3;r++)t.execCommand("goCharRight");else if("surround"==f){for(var i=t.getSelections(),r=0;r0,{anchor:new n(o.anchor.line,o.anchor.ch+(a?-1:1)),head:new n(o.head.line,o.head.ch+(a?1:-1))});t.setSelections(i)}else"both"==f?(t.replaceSelection(k+C,null),t.triggerElectric(k+C),t.execCommand("goCharLeft")):"addFour"==f&&(t.replaceSelection(k+k+k+k,"before"),t.execCommand("goCharRight"));var o,a})}(i,t)}}function l(e){var t=e.state.closeBrackets;if(!t||t.override)return t;var n=e.getModeAt(e.getCursor());return n.closeBrackets||t}function s(e,t){var n=t.lastIndexOf(e);return n>-1&&n%2==1}function c(e,t){var r=e.getRange(n(t.line,t.ch-1),n(t.line,t.ch+1));return 2==r.length?r:null}function u(e,t){var r=e.getTokenAt(n(t.line,t.ch+1));return/\bstring/.test(r.type)&&r.start==t.ch&&(0==t.ch||!/\bstring/.test(e.getTokenTypeAt(t)))}o(t.pairs+"`")}(n(0))},function(e,t,n){!function(e){"use strict";function t(e){return e.state.search||(e.state.search=new function(){this.posFrom=this.posTo=this.lastQuery=this.query=null,this.overlay=null})}function n(e){return"string"==typeof e&&e==e.toLowerCase()}function r(e,t,r){return e.getSearchCursor(t,r,{caseFold:n(t),multiline:!0})}function i(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0}):i(prompt(n,r))}function o(e){return e.replace(/\\(.)/g,function(e,t){return"n"==t?"\n":"r"==t?"\r":t})}function a(e){var t=e.match(/^\/(.*)\/([a-z]*)$/);if(t)try{e=new RegExp(t[1],-1==t[2].indexOf("i")?"":"i")}catch(e){}else e=o(e);return("string"==typeof e?""==e:e.test(""))&&(e=/x^/),e}var l;function s(e,t,r){t.queryText=r,t.query=a(r),e.removeOverlay(t.overlay,n(t.query)),t.overlay=function(e,t){return"string"==typeof e?e=new RegExp(e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),t?"gi":"g"):e.global||(e=new RegExp(e.source,e.ignoreCase?"gi":"g")),{token:function(t){e.lastIndex=t.pos;var n=e.exec(t.string);if(n&&n.index==t.pos)return t.pos+=n[0].length||1,"searching";n?t.pos=n.index:t.skipToEnd()}}}(t.query,n(t.query)),e.addOverlay(t.overlay),e.showMatchesOnScrollbar&&(t.annotate&&(t.annotate.clear(),t.annotate=null),t.annotate=e.showMatchesOnScrollbar(t.query,n(t.query)))}function c(n,r,o,a){if(!l){let e=n.getWrapperElement().ownerDocument,t=e.createElement("input");t.type="search",t.placeholder=n.l10n("findCmd.promptMessage"),t.style.marginInlineStart="1em",t.style.marginInlineEnd="1em",t.style.flexGrow="1",t.addEventListener("focus",()=>t.select()),(l=e.createElement("div")).appendChild(t),l.style.display="flex"}var c=t(n);if(c.query)return u(n,r);var d=n.getSelection()||c.lastQuery;if(d instanceof RegExp&&"x^"==d.source&&(d=null),o&&n.openDialog){var h=null,p=function(t,r){e.e_stop(r),t&&(t!=c.queryText&&(s(n,c,t),c.posFrom=c.posTo=n.getCursor()),h&&(h.style.opacity=1),u(n,r.shiftKey,function(e,t){var r;t.line<3&&document.querySelector&&(r=n.display.wrapper.querySelector(".CodeMirror-dialog"))&&r.getBoundingClientRect().bottom-4>n.cursorCoords(t,"window").top&&((h=r).style.opacity=.4)}))};!function(e,t,n,r,i){e.openDialog(t,r,{value:n,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){f(e)},onKeyDown:i})}(n,l,d,p,function(r,i){var o=e.keyName(r),a=n.getOption("extraKeys"),l=a&&a[o]||e.keyMap[n.getOption("keyMap")][o];"findNext"==l||"findPrev"==l||"findPersistentNext"==l||"findPersistentPrev"==l?(e.e_stop(r),s(n,t(n),i),n.execCommand(l)):"find"!=l&&"findPersistent"!=l||(e.e_stop(r),p(i,r))}),a&&d&&(s(n,c,d),u(n,r))}else i(n,l,"Search for:",d,function(e){e&&!c.query&&n.operation(function(){s(n,c,e),c.posFrom=c.posTo=n.getCursor(),u(n,r)})})}function u(n,i,o){n.operation(function(){var a=t(n),l=r(n,a.query,i?a.posFrom:a.posTo);(l.find(i)||(l=r(n,a.query,i?e.Pos(n.lastLine()):e.Pos(n.firstLine(),0))).find(i))&&(n.setSelection(l.from(),l.to()),n.scrollIntoView({from:l.from(),to:l.to()},20),a.posFrom=l.from(),a.posTo=l.to(),o&&o(l.from(),l.to()))})}function f(e){e.operation(function(){var n=t(e);n.lastQuery=n.query,n.query&&(n.query=n.queryText=null,e.removeOverlay(n.overlay),n.annotate&&(n.annotate.clear(),n.annotate=null))})}function d(e,t,n){e.operation(function(){for(var i=r(e,t);i.findNext();)if("string"!=typeof t){var o=e.getRange(i.from(),i.to()).match(t);i.replace(n.replace(/\$(\d)/g,function(e,t){return o[t]}))}else i.replace(n)})}function h(e,n){if(e.getOption("readOnly"))return;var l=e.getSelection()||t(e).lastQuery;let s=e.getWrapperElement().ownerDocument,c=s.createElement("span");c.classList.add("CodeMirror-search-label"),c.textContent=n?"Replace all:":"Replace:";let u=s.createDocumentFragment();u.appendChild(c.cloneNode(!0));let h=s.createElement("input");h.setAttribute("type","text"),h.setAttribute("style","width: 10em"),h.classList.add("CodeMirror-search-field"),u.appendChild(h);let p=s.createElement("span");p.setAttribute("style","color: #888"),p.classList.add("CodeMirror-search-hint"),p.textContent="(Use /re/ syntax for regexp search)",u.appendChild(p),i(e,u,c,l,function(t){if(!t)return;t=a(t);let l=s.createDocumentFragment(),u=c.cloneNode(!1);u.textContent="With:",l.appendChild(u);let h=s.createElement("input");h.setAttribute("type","text"),h.setAttribute("style","width: 10em"),h.classList.add("CodeMirror-search-field"),l.appendChild(h),i(e,l,"Replace with:","",function(i){if(i=o(i),n)d(e,t,i);else{f(e);var a=r(e,t,e.getCursor("from")),l=function(){var n,o=a.from();if(!(n=a.findNext())&&(a=r(e,t),!(n=a.findNext())||o&&a.from().line==o.line&&a.from().ch==o.ch))return;e.setSelection(a.from(),a.to()),e.scrollIntoView({from:a.from(),to:a.to()});let f=s.createDocumentFragment(),h=c.cloneNode(!1);h.textContent="Replace?",f.appendChild(h);let p=s.createElement("button");p.textContent="Yes",f.appendChild(p);let m=s.createElement("button");m.textContent="No",f.appendChild(m);let g=s.createElement("button");g.textContent="All",f.appendChild(g);let v=s.createElement("button");v.textContent="Stop",f.appendChild(v),function(e,t,n,r){e.openConfirm?e.openConfirm(t,r):confirm(n)&&r[0]()}(e,f,"Replace?",[function(){u(n)},l,function(){d(e,t,i)}])},u=function(e){a.replace("string"==typeof t?i:i.replace(/\$(\d)/g,function(t,n){return e[n]})),l()};l()}})})}e.commands.find=function(e){f(e),c(e)},e.commands.findPersistent=function(e){f(e),c(e,!1,!0)},e.commands.findPersistentNext=function(e){c(e,!1,!0,!0)},e.commands.findPersistentPrev=function(e){c(e,!0,!0,!0)},e.commands.findNext=c,e.commands.findPrev=function(e){c(e,!0)},e.commands.clearSearch=f,e.commands.replace=h,e.commands.replaceAll=function(e){h(e,!0)}}(n(0),n(1),n(5))},function(e,t,n){n(5),n(1),n(26),n(4),n(25),n(24),n(3),n(2),n(7),n(23),n(22),n(21),n(20),n(19),n(18),n(17),n(16),n(15),n(14),n(13),n(6),n(12),n(11),n(10),n(9),n(8),e.exports=n(0)}]); \ No newline at end of file diff --git a/devtools/client/sourceeditor/codemirror/lib/codemirror.js b/devtools/client/sourceeditor/codemirror/lib/codemirror.js index a491f1e3e44e..5f645466979d 100644 --- a/devtools/client/sourceeditor/codemirror/lib/codemirror.js +++ b/devtools/client/sourceeditor/codemirror/lib/codemirror.js @@ -746,6 +746,16 @@ function collapsedSpanAtSide(line, start) { function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } +function collapsedSpanAround(line, ch) { + var sps = sawCollapsedSpans && line.markedSpans, found + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i] + if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker } + } } + return found +} + // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. @@ -2778,12 +2788,11 @@ function coordsChar(cm, x, y) { var lineObj = getLine(doc, lineN) for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y) - var merged = collapsedSpanAtEnd(lineObj) - var mergedPos = merged && merged.find(0, true) - if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - { lineN = lineNo(lineObj = mergedPos.to.line) } - else - { return found } + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0)) + if (!collapsed) { return found } + var rangeEnd = collapsed.find(1) + if (rangeEnd.line == lineN) { return rangeEnd } + lineObj = getLine(doc, lineN = rangeEnd.line) } } @@ -3543,6 +3552,7 @@ var NativeScrollbars = function(place, scroll, cm) { this.cm = cm var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + vert.tabIndex = horiz.tabIndex = -1 place(vert); place(horiz) on(vert, "scroll", function () { @@ -7476,7 +7486,7 @@ function leftButtonSelect(cm, event, start, behavior) { } var move = operation(cm, function (e) { - if (!e_button(e)) { done(e) } + if (e.buttons === 0 || !e_button(e)) { done(e) } else { extend(e) } }) var up = operation(cm, done) @@ -8755,8 +8765,12 @@ ContentEditableInput.prototype.showSelection = function (info, takeFocus) { this.showMultipleSelections(info) }; +ContentEditableInput.prototype.getSelection = function () { + return this.cm.display.wrapper.ownerDocument.getSelection() +}; + ContentEditableInput.prototype.showPrimarySelection = function () { - var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() + var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() var from = prim.from(), to = prim.to() if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { @@ -8823,13 +8837,13 @@ ContentEditableInput.prototype.showMultipleSelections = function (info) { }; ContentEditableInput.prototype.rememberSelection = function () { - var sel = window.getSelection() + var sel = this.getSelection() this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset }; ContentEditableInput.prototype.selectionInEditor = function () { - var sel = window.getSelection() + var sel = this.getSelection() if (!sel.rangeCount) { return false } var node = sel.getRangeAt(0).commonAncestorContainer return contains(this.div, node) @@ -8864,14 +8878,14 @@ ContentEditableInput.prototype.receivedFocus = function () { }; ContentEditableInput.prototype.selectionChanged = function () { - var sel = window.getSelection() + var sel = this.getSelection() return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset }; ContentEditableInput.prototype.pollSelection = function () { if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } - var sel = window.getSelection(), cm = this.cm + var sel = this.getSelection(), cm = this.cm // On Android Chrome (version 56, at least), backspacing into an // uneditable block element will put the cursor in that element, // and then, because it's not editable, hide the virtual keyboard. @@ -9045,12 +9059,13 @@ function isInGutter(node) { function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator() + var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false function recognizeMarker(id) { return function (marker) { return marker.id == id; } } function close() { if (closing) { text += lineSep - closing = false + if (extraLinebreak) { text += lineSep } + closing = extraLinebreak = false } } function addText(str) { @@ -9062,8 +9077,8 @@ function domTextBetween(cm, from, to, fromLine, toLine) { function walk(node) { if (node.nodeType == 1) { var cmText = node.getAttribute("cm-text") - if (cmText != null) { - addText(cmText || node.textContent.replace(/\u200b/g, "")) + if (cmText) { + addText(cmText) return } var markerID = node.getAttribute("cm-marker"), range @@ -9074,19 +9089,24 @@ function domTextBetween(cm, from, to, fromLine, toLine) { return } if (node.getAttribute("contenteditable") == "false") { return } - var isBlock = /^(pre|div|p)$/i.test(node.nodeName) + var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName) + if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return } + if (isBlock) { close() } for (var i = 0; i < node.childNodes.length; i++) { walk(node.childNodes[i]) } + + if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true } if (isBlock) { closing = true } } else if (node.nodeType == 3) { - addText(node.nodeValue) + addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " ")) } } for (;;) { walk(from) if (from == to) { break } from = from.nextSibling + extraLinebreak = false } return text } @@ -9658,7 +9678,7 @@ CodeMirror.fromTextArea = fromTextArea addLegacyProps(CodeMirror) -CodeMirror.version = "5.37.0" +CodeMirror.version = "5.38.0" return CodeMirror; diff --git a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js index c4a709c62497..097c0bbe6d66 100644 --- a/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js +++ b/devtools/client/sourceeditor/codemirror/mode/javascript/javascript.js @@ -75,17 +75,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return ret(ch); } else if (ch == "=" && stream.eat(">")) { return ret("=>", "operator"); - } else if (ch == "0" && stream.eat(/x/i)) { - stream.eatWhile(/[\da-f]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/o/i)) { - stream.eatWhile(/[0-7]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/b/i)) { - stream.eatWhile(/[01]/i); + } else if (ch == "0" && stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i)) { return ret("number", "number"); } else if (/\d/.test(ch)) { - stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/); return ret("number", "number"); } else if (ch == "/") { if (stream.eat("*")) { @@ -96,7 +89,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return ret("comment", "comment"); } else if (expressionAllowed(stream, state, 1)) { readRegexp(stream); - stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); + stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/); return ret("regexp", "string-2"); } else { stream.eat("="); @@ -265,21 +258,42 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { pass.apply(null, arguments); return true; } + function inList(name, list) { + for (var v = list; v; v = v.next) if (v.name == name) return true + return false; + } function register(varname) { - function inList(list) { - for (var v = list; v; v = v.next) - if (v.name == varname) return true; - return false; - } var state = cx.state; cx.marked = "def"; if (state.context) { - if (inList(state.localVars)) return; - state.localVars = {name: varname, next: state.localVars}; + if (state.lexical.info == "var" && state.context && state.context.block) { + // FIXME function decls are also not block scoped + var newContext = registerVarScoped(varname, state.context) + if (newContext != null) { + state.context = newContext + return + } + } else if (!inList(varname, state.localVars)) { + state.localVars = new Var(varname, state.localVars) + return + } + } + // Fall through means this is global + if (parserConfig.globalVars && !inList(varname, state.globalVars)) + state.globalVars = new Var(varname, state.globalVars) + } + function registerVarScoped(varname, context) { + if (!context) { + return null + } else if (context.block) { + var inner = registerVarScoped(varname, context.prev) + if (!inner) return null + if (inner == context.prev) return context + return new Context(inner, context.vars, true) + } else if (inList(varname, context.vars)) { + return context } else { - if (inList(state.globalVars)) return; - if (parserConfig.globalVars) - state.globalVars = {name: varname, next: state.globalVars}; + return new Context(context.prev, new Var(varname, context.vars), false) } } @@ -289,15 +303,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { // Combinators - var defaultVars = {name: "this", next: {name: "arguments"}}; + function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block } + function Var(name, next) { this.name = name; this.next = next } + + var defaultVars = new Var("this", new Var("arguments", null)) function pushcontext() { - cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; - cx.state.localVars = defaultVars; + cx.state.context = new Context(cx.state.context, cx.state.localVars, false) + cx.state.localVars = defaultVars + } + function pushblockcontext() { + cx.state.context = new Context(cx.state.context, cx.state.localVars, true) + cx.state.localVars = null } function popcontext() { - cx.state.localVars = cx.state.context.vars; - cx.state.context = cx.state.context.prev; + cx.state.localVars = cx.state.context.vars + cx.state.context = cx.state.context.prev } + popcontext.lex = true function pushlex(type, info) { var result = function() { var state = cx.state, indent = state.indented; @@ -329,12 +351,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex); if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); if (type == "debugger") return cont(expect(";")); - if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext); if (type == ";") return cont(); if (type == "if") { if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) @@ -363,18 +385,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(pushlex("stat"), maybelabel); } } - if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), - block, poplex, poplex); + if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext, + block, poplex, poplex, popcontext); if (type == "case") return cont(expression, expect(":")); if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), - statement, poplex, popcontext); + if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext); if (type == "export") return cont(pushlex("stat"), afterExport, poplex); if (type == "import") return cont(pushlex("stat"), afterImport, poplex); if (type == "async") return cont(statement) if (value == "@") return cont(expression, statement) return pass(pushlex("stat"), expression, expect(";"), poplex); } + function maybeCatchBinding(type) { + if (type == "(") return cont(funarg, expect(")")) + } function expression(type, value) { return expressionInner(type, value, false); } @@ -783,7 +807,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { cc: [], lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), localVars: parserConfig.localVars, - context: parserConfig.localVars && {vars: parserConfig.localVars}, + context: parserConfig.localVars && new Context(null, null, false), indented: basecolumn || 0 }; if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") @@ -824,7 +848,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { lexical = lexical.prev; var type = lexical.type, closing = firstChar == type; - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0); else if (type == "form" && firstChar == "{") return lexical.indented; else if (type == "form") return lexical.indented + indentUnit; else if (type == "stat") diff --git a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js index 1885b79804aa..f8c95bf7ca76 100644 --- a/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js +++ b/devtools/client/sourceeditor/test/codemirror/mode/javascript/test.js @@ -86,6 +86,35 @@ " [keyword yield] [variable-2 i];", "}"); + MT("let_scoping", + "[keyword function] [def scoped]([def n]) {", + " { [keyword var] [def i]; } [variable-2 i];", + " { [keyword let] [def j]; [variable-2 j]; } [variable j];", + " [keyword if] ([atom true]) { [keyword const] [def k]; [variable-2 k]; } [variable k];", + "}"); + + MT("switch_scoping", + "[keyword switch] ([variable x]) {", + " [keyword default]:", + " [keyword let] [def j];", + " [keyword return] [variable-2 j]", + "}", + "[variable j];") + + MT("leaving_scope", + "[keyword function] [def a]() {", + " {", + " [keyword const] [def x] [operator =] [number 1]", + " [keyword if] ([atom true]) {", + " [keyword let] [def y] [operator =] [number 2]", + " [keyword var] [def z] [operator =] [number 3]", + " [variable console].[property log]([variable-2 x], [variable-2 y], [variable-2 z])", + " }", + " [variable console].[property log]([variable-2 x], [variable y], [variable-2 z])", + " }", + " [variable console].[property log]([variable x], [variable y], [variable-2 z])", + "}") + MT("quotedStringAddition", "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); @@ -239,6 +268,8 @@ "[keyword const] [def async] [operator =] {[property a]: [number 1]};", "[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];") + MT("bigint", "[number 1n] [operator +] [number 0x1afn] [operator +] [number 0o064n] [operator +] [number 0b100n];") + MT("async_comment", "[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); diff --git a/devtools/client/sourceeditor/test/codemirror/test.js b/devtools/client/sourceeditor/test/codemirror/test.js index 415dd9f0bc5d..a646a0ce19eb 100644 --- a/devtools/client/sourceeditor/test/codemirror/test.js +++ b/devtools/client/sourceeditor/test/codemirror/test.js @@ -889,6 +889,15 @@ testCM("hiddenLinesSelectAll", function(cm) { // Issue #484 eqCursorPos(cm.getCursor(false), Pos(10, 4)); }); +testCM("clickFold", function(cm) { // Issue #5392 + cm.setValue("foo { bar }") + var widget = document.createElement("span") + widget.textContent = "<>" + cm.markText(Pos(0, 5), Pos(0, 10), {replacedWith: widget}) + var after = cm.charCoords(Pos(0, 10)) + var foundOn = cm.coordsChar({left: after.left - 1, top: after.top + 4}) + is(foundOn.ch <= 5 || foundOn.ch >= 10, "Position is not inside the folded range") +}) testCM("everythingFolded", function(cm) { addDoc(cm, 2, 2); From 08be40bcc5414a1f1ee482ea1a016028b54873c4 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 13:36:34 -0700 Subject: [PATCH 078/116] Bug 1465103 Convert service worker and clients release assertions to diagnostic assertions. r=asuth --- dom/clients/manager/ClientHandle.cpp | 4 +- dom/clients/manager/ClientHandleOpChild.cpp | 6 +-- dom/clients/manager/ClientManager.cpp | 41 +++++++++++++-------- dom/clients/manager/ClientThing.h | 12 +++++- dom/serviceworkers/ServiceWorkerManager.cpp | 2 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/dom/clients/manager/ClientHandle.cpp b/dom/clients/manager/ClientHandle.cpp index 7bb58418e296..74383b88ff2b 100644 --- a/dom/clients/manager/ClientHandle.cpp +++ b/dom/clients/manager/ClientHandle.cpp @@ -50,7 +50,7 @@ ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs, MaybeExecute([aArgs, kungFuGrip, aRejectCallback, resolve = std::move(aResolveCallback)] (ClientHandleChild* aActor) { - MOZ_RELEASE_ASSERT(aActor); + MOZ_DIAGNOSTIC_ASSERT(aActor); ClientHandleOpChild* actor = new ClientHandleOpChild(kungFuGrip, aArgs, std::move(resolve), std::move(aRejectCallback)); @@ -59,7 +59,7 @@ ClientHandle::StartOp(const ClientOpConstructorArgs& aArgs, return; } }, [aRejectCallback] { - MOZ_RELEASE_ASSERT(aRejectCallback); + MOZ_DIAGNOSTIC_ASSERT(aRejectCallback); aRejectCallback(NS_ERROR_DOM_INVALID_STATE_ERR); }); } diff --git a/dom/clients/manager/ClientHandleOpChild.cpp b/dom/clients/manager/ClientHandleOpChild.cpp index 8cd1cc34fbcb..1929e76516ca 100644 --- a/dom/clients/manager/ClientHandleOpChild.cpp +++ b/dom/clients/manager/ClientHandleOpChild.cpp @@ -39,9 +39,9 @@ ClientHandleOpChild::ClientHandleOpChild(ClientHandle* aClientHandle, , mResolveCallback(std::move(aResolveCallback)) , mRejectCallback(std::move(aRejectCallback)) { - MOZ_RELEASE_ASSERT(mClientHandle); - MOZ_RELEASE_ASSERT(mResolveCallback); - MOZ_RELEASE_ASSERT(mRejectCallback); + MOZ_DIAGNOSTIC_ASSERT(mClientHandle); + MOZ_DIAGNOSTIC_ASSERT(mResolveCallback); + MOZ_DIAGNOSTIC_ASSERT(mRejectCallback); } } // namespace dom diff --git a/dom/clients/manager/ClientManager.cpp b/dom/clients/manager/ClientManager.cpp index 0e98e503ea5a..0ba8c0a64078 100644 --- a/dom/clients/manager/ClientManager.cpp +++ b/dom/clients/manager/ClientManager.cpp @@ -28,12 +28,21 @@ using mozilla::ipc::PrincipalInfo; namespace { const uint32_t kBadThreadLocalIndex = -1; +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED const uint32_t kThreadLocalMagic1 = 0x8d57eea6; const uint32_t kThreadLocalMagic2 = 0x59f375c9; +#endif + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED uint32_t sClientManagerThreadLocalMagic1 = kThreadLocalMagic1; +#endif + uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex; + +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED uint32_t sClientManagerThreadLocalMagic2 = kThreadLocalMagic2; uint32_t sClientManagerThreadLocalIndexDuplicate = kBadThreadLocalIndex; +#endif } // anonymous namespace @@ -84,11 +93,11 @@ ClientManager::~ClientManager() Shutdown(); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); - MOZ_RELEASE_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex)); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); + MOZ_DIAGNOSTIC_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex)); #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED PRStatus status = @@ -194,10 +203,10 @@ ClientManager::StartOp(const ClientOpConstructorArgs& aArgs, already_AddRefed ClientManager::GetOrCreateForCurrentThread() { - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); RefPtr cm = static_cast(PR_GetThreadPrivate(sClientManagerThreadLocalIndex)); @@ -211,7 +220,7 @@ ClientManager::GetOrCreateForCurrentThread() MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS); } - MOZ_RELEASE_ASSERT(cm); + MOZ_DIAGNOSTIC_ASSERT(cm); return cm.forget(); } @@ -229,10 +238,10 @@ ClientManager::Startup() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate); #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED PRStatus status = @@ -240,8 +249,10 @@ ClientManager::Startup() PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr); MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS); - MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); + MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED sClientManagerThreadLocalIndexDuplicate = sClientManagerThreadLocalIndex; +#endif ClientPrefsInit(); } diff --git a/dom/clients/manager/ClientThing.h b/dom/clients/manager/ClientThing.h index 573a5c11218a..37560034818e 100644 --- a/dom/clients/manager/ClientThing.h +++ b/dom/clients/manager/ClientThing.h @@ -17,19 +17,25 @@ namespace dom { template class ClientThing { +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED static const uint32_t kMagic1 = 0xC9FE2C9C; static const uint32_t kMagic2 = 0x832072D4; +#endif ActorType* mActor; +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED uint32_t mMagic1; uint32_t mMagic2; +#endif bool mShutdown; protected: ClientThing() : mActor(nullptr) +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED , mMagic1(kMagic1) , mMagic2(kMagic2) +#endif , mShutdown(false) { } @@ -38,15 +44,17 @@ protected: { AssertIsValid(); ShutdownThing(); +#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED mMagic1 = 0; mMagic2 = 0; +#endif } void AssertIsValid() const { - MOZ_RELEASE_ASSERT(mMagic1 == kMagic1); - MOZ_RELEASE_ASSERT(mMagic2 == kMagic2); + MOZ_DIAGNOSTIC_ASSERT(mMagic1 == kMagic1); + MOZ_DIAGNOSTIC_ASSERT(mMagic2 == kMagic2); } // Return the current actor. diff --git a/dom/serviceworkers/ServiceWorkerManager.cpp b/dom/serviceworkers/ServiceWorkerManager.cpp index 26d7b0f41763..9604407f5ac2 100644 --- a/dom/serviceworkers/ServiceWorkerManager.cpp +++ b/dom/serviceworkers/ServiceWorkerManager.cpp @@ -312,7 +312,7 @@ RefPtr ServiceWorkerManager::StartControllingClient(const ClientInfo& aClientInfo, ServiceWorkerRegistrationInfo* aRegistrationInfo) { - MOZ_RELEASE_ASSERT(aRegistrationInfo->GetActive()); + MOZ_DIAGNOSTIC_ASSERT(aRegistrationInfo->GetActive()); RefPtr ref; From 126df200a98feac60a9e21c497a8e043c2b49b82 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 13:39:56 -0700 Subject: [PATCH 079/116] Bug 1462069 P0 Allow ServiceWorkerParentInterceptEnabled() to be used off-main-thread. r=asuth --- dom/serviceworkers/ServiceWorkerUtils.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/dom/serviceworkers/ServiceWorkerUtils.cpp b/dom/serviceworkers/ServiceWorkerUtils.cpp index 421a25519bc7..a000d58abb07 100644 --- a/dom/serviceworkers/ServiceWorkerUtils.cpp +++ b/dom/serviceworkers/ServiceWorkerUtils.cpp @@ -14,18 +14,14 @@ namespace dom { bool ServiceWorkerParentInterceptEnabled() { - // For right now we only support main thread. In the future we could make - // this use an atomic bool if we need to support worker threads. - MOZ_ASSERT(NS_IsMainThread()); - static bool sInit = false; - static bool sEnabled; + static Atomic sEnabled; if (!sInit) { MOZ_ASSERT(NS_IsMainThread()); - Preferences::AddBoolVarCache(&sEnabled, - "dom.serviceWorkers.parent_intercept", - false); + Preferences::AddAtomicBoolVarCache(&sEnabled, + "dom.serviceWorkers.parent_intercept", + false); sInit = true; } From 6d1736c617f3f0454c89f41e3469741e769951e3 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 13:39:57 -0700 Subject: [PATCH 080/116] Bug 1462069 P1 Make ServiceWorkerManager::MaybeClaimClient() take a ClientInfo instead of nsIDocument. r=baku --- dom/clients/manager/ClientSource.cpp | 2 +- dom/serviceworkers/ServiceWorkerManager.cpp | 26 +++++++-------------- dom/serviceworkers/ServiceWorkerManager.h | 4 ++-- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/dom/clients/manager/ClientSource.cpp b/dom/clients/manager/ClientSource.cpp index c0357b25adea..ec498691cdb9 100644 --- a/dom/clients/manager/ClientSource.cpp +++ b/dom/clients/manager/ClientSource.cpp @@ -640,7 +640,7 @@ ClientSource::Claim(const ClientClaimArgs& aArgs) auto holder = MakeRefPtr>(innerWindow->AsGlobal()); - RefPtr p = swm->MaybeClaimClient(doc, swd); + RefPtr p = swm->MaybeClaimClient(mClientInfo, swd); p->Then(mEventTarget, __func__, [outerPromise, holder] (bool aResult) { holder->Complete(); diff --git a/dom/serviceworkers/ServiceWorkerManager.cpp b/dom/serviceworkers/ServiceWorkerManager.cpp index 9604407f5ac2..1dd43b9d831e 100644 --- a/dom/serviceworkers/ServiceWorkerManager.cpp +++ b/dom/serviceworkers/ServiceWorkerManager.cpp @@ -2554,7 +2554,7 @@ ServiceWorkerManager::UpdateInternal(nsIPrincipal* aPrincipal, } already_AddRefed -ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument, +ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, ServiceWorkerRegistrationInfo* aWorkerRegistration) { MOZ_DIAGNOSTIC_ASSERT(aWorkerRegistration); @@ -2568,26 +2568,19 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument, } // Same origin check - if (!aWorkerRegistration->Principal()->Equals(aDocument->NodePrincipal())) { + nsCOMPtr principal(aClientInfo.GetPrincipal()); + if (!aWorkerRegistration->Principal()->Equals(principal)) { ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_SECURITY_ERR, __func__); return ref.forget(); } - Maybe clientInfo(aDocument->GetClientInfo()); - if (NS_WARN_IF(clientInfo.isNothing())) { - ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, - __func__); - return ref.forget(); - } - // The registration that should be controlling the client RefPtr matchingRegistration = - GetServiceWorkerRegistrationInfo(aDocument); + GetServiceWorkerRegistrationInfo(aClientInfo); // The registration currently controlling the client RefPtr controllingRegistration; - GetClientRegistration(clientInfo.ref(), - getter_AddRefs(controllingRegistration)); + GetClientRegistration(aClientInfo, getter_AddRefs(controllingRegistration)); if (aWorkerRegistration != matchingRegistration || aWorkerRegistration == controllingRegistration) { @@ -2595,18 +2588,17 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument, return ref.forget(); } - ref = StartControllingClient(clientInfo.ref(), aWorkerRegistration); + ref = StartControllingClient(aClientInfo, aWorkerRegistration); return ref.forget(); } already_AddRefed -ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDoc, +ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, const ServiceWorkerDescriptor& aServiceWorker) { RefPtr ref; - nsCOMPtr principal = - PrincipalInfoToPrincipal(aServiceWorker.PrincipalInfo()); + nsCOMPtr principal = aServiceWorker.GetPrincipal(); if (!principal) { ref = GenericPromise::CreateAndResolve(false, __func__); return ref.forget(); @@ -2625,7 +2617,7 @@ ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDoc, return ref.forget(); } - ref = MaybeClaimClient(aDoc, registration); + ref = MaybeClaimClient(aClientInfo, registration); return ref.forget(); } diff --git a/dom/serviceworkers/ServiceWorkerManager.h b/dom/serviceworkers/ServiceWorkerManager.h index ead91b04b128..18db8b8c7633 100644 --- a/dom/serviceworkers/ServiceWorkerManager.h +++ b/dom/serviceworkers/ServiceWorkerManager.h @@ -285,11 +285,11 @@ public: JSExnType aExnType); already_AddRefed - MaybeClaimClient(nsIDocument* aDocument, + MaybeClaimClient(const ClientInfo& aClientInfo, ServiceWorkerRegistrationInfo* aWorkerRegistration); already_AddRefed - MaybeClaimClient(nsIDocument* aDoc, + MaybeClaimClient(const ClientInfo& aClientInfo, const ServiceWorkerDescriptor& aServiceWorker); void From 9e0e3a5c878785e0b4556e825dda8f7672895e8c Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 1 Jun 2018 13:39:57 -0700 Subject: [PATCH 081/116] Bug 1462069 P2 Make ClientManagerService forward claim() requests to the main thread SWM when the pref is set. r=baku --- dom/clients/manager/ClientManagerService.cpp | 44 +++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/dom/clients/manager/ClientManagerService.cpp b/dom/clients/manager/ClientManagerService.cpp index 38e4bf7041e4..bd826d53ebd7 100644 --- a/dom/clients/manager/ClientManagerService.cpp +++ b/dom/clients/manager/ClientManagerService.cpp @@ -13,6 +13,8 @@ #include "ClientPrincipalUtils.h" #include "ClientSourceParent.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ServiceWorkerManager.h" +#include "mozilla/dom/ServiceWorkerUtils.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/ClearOnShutdown.h" @@ -448,6 +450,40 @@ ClientManagerService::MatchAll(const ClientMatchAllArgs& aArgs) return promiseList->GetResultPromise(); } +namespace { + +RefPtr +ClaimOnMainThread(const ClientInfo& aClientInfo, + const ServiceWorkerDescriptor& aDescriptor) +{ + RefPtr promise = + new ClientOpPromise::Private(__func__); + + nsCOMPtr r = NS_NewRunnableFunction(__func__, + [promise, clientInfo = Move(aClientInfo), desc = Move(aDescriptor)] () { + auto scopeExit = MakeScopeExit([&] { + promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); + }); + + RefPtr swm = ServiceWorkerManager::GetInstance(); + NS_ENSURE_TRUE_VOID(swm); + + RefPtr inner = swm->MaybeClaimClient(clientInfo, desc); + inner->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__, + [promise] (bool aResult) { + promise->Resolve(NS_OK, __func__); + }, [promise] (nsresult aRv) { + promise->Reject(aRv, __func__); + }); + }); + + MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget())); + + return promise.forget(); +} + +} // anonymous namespace + RefPtr ClientManagerService::Claim(const ClientClaimArgs& aArgs) { @@ -487,7 +523,13 @@ ClientManagerService::Claim(const ClientClaimArgs& aArgs) continue; } - promiseList->AddPromise(source->StartOp(aArgs)); + if (ServiceWorkerParentInterceptEnabled()) { + promiseList->AddPromise( + ClaimOnMainThread(source->Info(), + ServiceWorkerDescriptor(serviceWorker))); + } else { + promiseList->AddPromise(source->StartOp(aArgs)); + } } // Maybe finish the promise now in case we didn't find any matching clients. From dd2e67b482c4e3c4870324f990a1699e1b7fabe7 Mon Sep 17 00:00:00 2001 From: Gurzau Raul Date: Fri, 1 Jun 2018 23:57:36 +0300 Subject: [PATCH 082/116] Backed out 3 changesets (bug 1462069) for build bustage on /src/dom/clients/manager/ClientManagerService.cpp on a CLOSED TREE Backed out changeset 999be9379af3 (bug 1462069) Backed out changeset 457cb3f8a0d9 (bug 1462069) Backed out changeset ec66aff745a8 (bug 1462069) --- dom/clients/manager/ClientManagerService.cpp | 44 +------------------- dom/clients/manager/ClientSource.cpp | 2 +- dom/serviceworkers/ServiceWorkerManager.cpp | 26 ++++++++---- dom/serviceworkers/ServiceWorkerManager.h | 4 +- dom/serviceworkers/ServiceWorkerUtils.cpp | 12 ++++-- 5 files changed, 29 insertions(+), 59 deletions(-) diff --git a/dom/clients/manager/ClientManagerService.cpp b/dom/clients/manager/ClientManagerService.cpp index bd826d53ebd7..38e4bf7041e4 100644 --- a/dom/clients/manager/ClientManagerService.cpp +++ b/dom/clients/manager/ClientManagerService.cpp @@ -13,8 +13,6 @@ #include "ClientPrincipalUtils.h" #include "ClientSourceParent.h" #include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/ServiceWorkerManager.h" -#include "mozilla/dom/ServiceWorkerUtils.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/ClearOnShutdown.h" @@ -450,40 +448,6 @@ ClientManagerService::MatchAll(const ClientMatchAllArgs& aArgs) return promiseList->GetResultPromise(); } -namespace { - -RefPtr -ClaimOnMainThread(const ClientInfo& aClientInfo, - const ServiceWorkerDescriptor& aDescriptor) -{ - RefPtr promise = - new ClientOpPromise::Private(__func__); - - nsCOMPtr r = NS_NewRunnableFunction(__func__, - [promise, clientInfo = Move(aClientInfo), desc = Move(aDescriptor)] () { - auto scopeExit = MakeScopeExit([&] { - promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); - }); - - RefPtr swm = ServiceWorkerManager::GetInstance(); - NS_ENSURE_TRUE_VOID(swm); - - RefPtr inner = swm->MaybeClaimClient(clientInfo, desc); - inner->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__, - [promise] (bool aResult) { - promise->Resolve(NS_OK, __func__); - }, [promise] (nsresult aRv) { - promise->Reject(aRv, __func__); - }); - }); - - MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget())); - - return promise.forget(); -} - -} // anonymous namespace - RefPtr ClientManagerService::Claim(const ClientClaimArgs& aArgs) { @@ -523,13 +487,7 @@ ClientManagerService::Claim(const ClientClaimArgs& aArgs) continue; } - if (ServiceWorkerParentInterceptEnabled()) { - promiseList->AddPromise( - ClaimOnMainThread(source->Info(), - ServiceWorkerDescriptor(serviceWorker))); - } else { - promiseList->AddPromise(source->StartOp(aArgs)); - } + promiseList->AddPromise(source->StartOp(aArgs)); } // Maybe finish the promise now in case we didn't find any matching clients. diff --git a/dom/clients/manager/ClientSource.cpp b/dom/clients/manager/ClientSource.cpp index ec498691cdb9..c0357b25adea 100644 --- a/dom/clients/manager/ClientSource.cpp +++ b/dom/clients/manager/ClientSource.cpp @@ -640,7 +640,7 @@ ClientSource::Claim(const ClientClaimArgs& aArgs) auto holder = MakeRefPtr>(innerWindow->AsGlobal()); - RefPtr p = swm->MaybeClaimClient(mClientInfo, swd); + RefPtr p = swm->MaybeClaimClient(doc, swd); p->Then(mEventTarget, __func__, [outerPromise, holder] (bool aResult) { holder->Complete(); diff --git a/dom/serviceworkers/ServiceWorkerManager.cpp b/dom/serviceworkers/ServiceWorkerManager.cpp index 1dd43b9d831e..9604407f5ac2 100644 --- a/dom/serviceworkers/ServiceWorkerManager.cpp +++ b/dom/serviceworkers/ServiceWorkerManager.cpp @@ -2554,7 +2554,7 @@ ServiceWorkerManager::UpdateInternal(nsIPrincipal* aPrincipal, } already_AddRefed -ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, +ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDocument, ServiceWorkerRegistrationInfo* aWorkerRegistration) { MOZ_DIAGNOSTIC_ASSERT(aWorkerRegistration); @@ -2568,19 +2568,26 @@ ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, } // Same origin check - nsCOMPtr principal(aClientInfo.GetPrincipal()); - if (!aWorkerRegistration->Principal()->Equals(principal)) { + if (!aWorkerRegistration->Principal()->Equals(aDocument->NodePrincipal())) { ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_SECURITY_ERR, __func__); return ref.forget(); } + Maybe clientInfo(aDocument->GetClientInfo()); + if (NS_WARN_IF(clientInfo.isNothing())) { + ref = GenericPromise::CreateAndReject(NS_ERROR_DOM_INVALID_STATE_ERR, + __func__); + return ref.forget(); + } + // The registration that should be controlling the client RefPtr matchingRegistration = - GetServiceWorkerRegistrationInfo(aClientInfo); + GetServiceWorkerRegistrationInfo(aDocument); // The registration currently controlling the client RefPtr controllingRegistration; - GetClientRegistration(aClientInfo, getter_AddRefs(controllingRegistration)); + GetClientRegistration(clientInfo.ref(), + getter_AddRefs(controllingRegistration)); if (aWorkerRegistration != matchingRegistration || aWorkerRegistration == controllingRegistration) { @@ -2588,17 +2595,18 @@ ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, return ref.forget(); } - ref = StartControllingClient(aClientInfo, aWorkerRegistration); + ref = StartControllingClient(clientInfo.ref(), aWorkerRegistration); return ref.forget(); } already_AddRefed -ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, +ServiceWorkerManager::MaybeClaimClient(nsIDocument* aDoc, const ServiceWorkerDescriptor& aServiceWorker) { RefPtr ref; - nsCOMPtr principal = aServiceWorker.GetPrincipal(); + nsCOMPtr principal = + PrincipalInfoToPrincipal(aServiceWorker.PrincipalInfo()); if (!principal) { ref = GenericPromise::CreateAndResolve(false, __func__); return ref.forget(); @@ -2617,7 +2625,7 @@ ServiceWorkerManager::MaybeClaimClient(const ClientInfo& aClientInfo, return ref.forget(); } - ref = MaybeClaimClient(aClientInfo, registration); + ref = MaybeClaimClient(aDoc, registration); return ref.forget(); } diff --git a/dom/serviceworkers/ServiceWorkerManager.h b/dom/serviceworkers/ServiceWorkerManager.h index 18db8b8c7633..ead91b04b128 100644 --- a/dom/serviceworkers/ServiceWorkerManager.h +++ b/dom/serviceworkers/ServiceWorkerManager.h @@ -285,11 +285,11 @@ public: JSExnType aExnType); already_AddRefed - MaybeClaimClient(const ClientInfo& aClientInfo, + MaybeClaimClient(nsIDocument* aDocument, ServiceWorkerRegistrationInfo* aWorkerRegistration); already_AddRefed - MaybeClaimClient(const ClientInfo& aClientInfo, + MaybeClaimClient(nsIDocument* aDoc, const ServiceWorkerDescriptor& aServiceWorker); void diff --git a/dom/serviceworkers/ServiceWorkerUtils.cpp b/dom/serviceworkers/ServiceWorkerUtils.cpp index a000d58abb07..421a25519bc7 100644 --- a/dom/serviceworkers/ServiceWorkerUtils.cpp +++ b/dom/serviceworkers/ServiceWorkerUtils.cpp @@ -14,14 +14,18 @@ namespace dom { bool ServiceWorkerParentInterceptEnabled() { + // For right now we only support main thread. In the future we could make + // this use an atomic bool if we need to support worker threads. + MOZ_ASSERT(NS_IsMainThread()); + static bool sInit = false; - static Atomic sEnabled; + static bool sEnabled; if (!sInit) { MOZ_ASSERT(NS_IsMainThread()); - Preferences::AddAtomicBoolVarCache(&sEnabled, - "dom.serviceWorkers.parent_intercept", - false); + Preferences::AddBoolVarCache(&sEnabled, + "dom.serviceWorkers.parent_intercept", + false); sInit = true; } From 373a1ed449a0f52bf7d76d92eeb52c900c56a90d Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Thu, 29 Mar 2018 17:28:56 -0700 Subject: [PATCH 083/116] Bug 1466001 - Index buffer must be non-null. - r=kvark MozReview-Commit-ID: ConbNwht4Pp --- dom/canvas/WebGLContextDraw.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dom/canvas/WebGLContextDraw.cpp b/dom/canvas/WebGLContextDraw.cpp index 3f179477b3bc..a33cb3b271d4 100644 --- a/dom/canvas/WebGLContextDraw.cpp +++ b/dom/canvas/WebGLContextDraw.cpp @@ -675,18 +675,19 @@ WebGLContext::DrawElements_check(const char* const funcName, const GLsizei rawIn //// // Index fetching + const auto& indexBuffer = mBoundVertexArray->mElementArrayBuffer; + if (!indexBuffer) { + ErrorInvalidOperation("%s: Index buffer not bound.", funcName); + return false; + } + MOZ_ASSERT(!indexBuffer->IsBoundForTF(), "This should be impossible."); + if (!indexCount || !instanceCount) { *out_lastVert = Nothing(); return true; } - const auto& indexBuffer = mBoundVertexArray->mElementArrayBuffer; - - size_t availBytes = 0; - if (indexBuffer) { - MOZ_ASSERT(!indexBuffer->IsBoundForTF(), "This should be impossible."); - availBytes = indexBuffer->ByteLength(); - } + const size_t availBytes = indexBuffer->ByteLength(); const auto availIndices = AvailGroups(availBytes, byteOffset, bytesPerIndex, bytesPerIndex); if (indexCount > availIndices) { From 2a43b97af6d5ffbf46fe80c37e4d388b159ef7ee Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 2 Jun 2018 00:08:26 +0200 Subject: [PATCH 084/116] Bug 1462854 part 1 - Factor out "percentage on replaced box that should resolve against zero" test (idempotent patch). r=dholbert --- layout/base/nsLayoutUtils.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index f07813a589ca..2c19e104bbe8 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5088,6 +5088,21 @@ FormControlShrinksForPercentISize(nsIFrame* aFrame) return true; } +// https://drafts.csswg.org/css-sizing-3/#percentage-sizing +// Return true if the above spec's rule for replaced boxes applies. +// XXX bug 1463700 will make this match the spec... +static bool +IsReplacedBoxResolvedAgainstZero(nsIFrame* aFrame, + const nsStyleCoord& aStyleSize, + const nsStyleCoord& aStyleMaxSize) +{ + const bool sizeHasPercent = aStyleSize.HasPercent(); + return ((sizeHasPercent || aStyleMaxSize.HasPercent()) && + aFrame->IsFrameOfType(nsIFrame::eReplacedSizing)) || + (sizeHasPercent && + FormControlShrinksForPercentISize(aFrame)); +} + /** * Add aOffsets which describes what to add on outside of the content box * aContentSize (controlled by 'box-sizing') and apply min/max properties. @@ -5149,16 +5164,8 @@ AddIntrinsicSizeOffset(gfxContext* aRenderingContext, nscoord size; if (aType == nsLayoutUtils::MIN_ISIZE && - (((aStyleSize.HasPercent() || aStyleMaxSize.HasPercent()) && - aFrame->IsFrameOfType(nsIFrame::eReplacedSizing)) || - (aStyleSize.HasPercent() && - FormControlShrinksForPercentISize(aFrame)))) { - // A percentage width or max-width on replaced elements means they - // can shrink to 0. - // This is also true for percentage widths (but not max-widths) on - // text inputs. - // Note that if this is max-width, this overrides the fixed-width - // rule in the next condition. + ::IsReplacedBoxResolvedAgainstZero(aFrame, aStyleSize, aStyleMaxSize)) { + // XXX bug 1463700: this doesn't handle calc() according to spec result = 0; // let |min| handle padding/border/margin } else if (GetAbsoluteCoord(aStyleSize, size) || GetIntrinsicCoord(aStyleSize, aRenderingContext, aFrame, From 79a2430c0131dcc2785ba8866fdb515d3f704240 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 2 Jun 2018 00:08:26 +0200 Subject: [PATCH 085/116] Bug 1462854 part 2 - [css-grid] Handle [max-]width/height percentages in min-size contributions according to spec. r=dholbert Background: https://github.com/w3c/csswg-drafts/issues/2674 calc() percentages for replaced boxes are still not according to spec. Bug 1463700 will fix that. --- layout/base/nsLayoutUtils.cpp | 6 ++++++ layout/generic/nsGridContainerFrame.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 2c19e104bbe8..7fabbc6bc403 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -5529,6 +5529,12 @@ nsLayoutUtils::MinSizeContributionForAxis(PhysicalAxis aAxis, // We have a definite width/height. This is the "specified size" in: // https://drafts.csswg.org/css-grid/#min-size-auto fixedMinSize = &minSize; + } else if (::IsReplacedBoxResolvedAgainstZero(aFrame, *style, + eAxisHorizontal ? stylePos->mMaxWidth + : stylePos->mMaxHeight)) { + // XXX bug 1463700: this doesn't handle calc() according to spec + minSize = 0; + fixedMinSize = &minSize; } // fall through - the caller will have to deal with "transferred size" } else { diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index a97b9dc2efdb..4b9b07ac4ef1 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -3715,7 +3715,7 @@ MaxContentContribution(const GridItemInfo& aGridItem, } // Computes the min-size contribution for a grid item, as defined at -// https://drafts.csswg.org/css-grid/#min-size-contributions +// https://drafts.csswg.org/css-grid/#min-size-contribution static nscoord MinSize(const GridItemInfo& aGridItem, const GridReflowInput& aState, @@ -3732,7 +3732,7 @@ MinSize(const GridItemInfo& aGridItem, const nsStylePosition* stylePos = child->StylePosition(); const nsStyleCoord& sizeStyle = axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight; - if (sizeStyle.GetUnit() != eStyleUnit_Auto) { + if (sizeStyle.GetUnit() != eStyleUnit_Auto && !sizeStyle.HasPercent()) { nscoord s = MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache); aCache->mMinSize.emplace(s); From 9a0e86481cda2f583fb1d5a4b523688c94cea81b Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 2 Jun 2018 00:08:26 +0200 Subject: [PATCH 086/116] Bug 1462854 part 3 - [css-grid] Update reftest reference. --- .../grid-item-overflow-stretch-004-ref.html | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/layout/reftests/css-grid/grid-item-overflow-stretch-004-ref.html b/layout/reftests/css-grid/grid-item-overflow-stretch-004-ref.html index cb1b662f6338..9e652f9eb876 100644 --- a/layout/reftests/css-grid/grid-item-overflow-stretch-004-ref.html +++ b/layout/reftests/css-grid/grid-item-overflow-stretch-004-ref.html @@ -18,8 +18,8 @@ body,html { color:black; background:white; font:16px/1 monospace; padding:0; mar grid-gap: 5px; border:1px solid; } -.c2 { grid: 7px 30x 3px / 7px 112px 3px; grid-gap: 5px;} -.c3 { grid: 7px 30x 3px / 7px 70px 3px; grid-gap: 5px;} +.c2 { grid: 7px 30px 3px / 7px 112px 3px; grid-gap: 5px;} +.c3 { grid: 7px 30px 3px / 7px 70px 3px; grid-gap: 5px;} .grid > * { grid-area: 2/2; @@ -33,9 +33,7 @@ body,html { color:black; background:white; font:16px/1 monospace; padding:0; mar justify-self: safe center; align-self: safe center; } -.h > .grid { grid: 7px 102px 3px / 7px 70px 3px; grid-gap: 5px;} -.h > .grid.c2 { grid: 7px 30px 3px / 7px 70px 3px; grid-gap: 5px;} -.h > .grid.c3 { grid: 7px 108px 3px / 7px 70px 3px; grid-gap: 5px;} +.h > .grid { grid: 7px 30px 3px / 7px 70px 3px; grid-gap: 5px; } .oa { overflow: auto; } .p { width: 100%; } @@ -52,8 +50,8 @@ br { clear:both; } -
-
+
+
@@ -70,15 +68,15 @@ br { clear:both; }
-
-
+
+

-
-
-
-
+
+
+
+

From 2884d63e5235c76849a4b17b767a4dd4c3fda8d1 Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Wed, 23 May 2018 16:50:49 -0600 Subject: [PATCH 087/116] Bug 1463596: Ensure that WritableTargetFunction correctly handles changing of protection attributes across regions that straddle page boundaries and have different initial protection attributes; r=handyman --- mozglue/misc/interceptor/TargetFunction.h | 108 ++++++++++++++++++---- 1 file changed, 92 insertions(+), 16 deletions(-) diff --git a/mozglue/misc/interceptor/TargetFunction.h b/mozglue/misc/interceptor/TargetFunction.h index ef00eb90cc3d..66bfea49facd 100644 --- a/mozglue/misc/interceptor/TargetFunction.h +++ b/mozglue/misc/interceptor/TargetFunction.h @@ -10,7 +10,9 @@ #include "mozilla/Assertions.h" #include "mozilla/Attributes.h" #include "mozilla/Maybe.h" +#include "mozilla/Tuple.h" #include "mozilla/Types.h" +#include "mozilla/Vector.h" #include @@ -20,6 +22,91 @@ namespace interceptor { template class MOZ_STACK_CLASS WritableTargetFunction final { + class AutoProtect final + { + using ProtectParams = Tuple; + + public: + explicit AutoProtect(const MMPolicy& aMMPolicy) + : mMMPolicy(aMMPolicy) + { + } + + AutoProtect(const MMPolicy& aMMPolicy, uintptr_t aAddr, size_t aNumBytes, + uint32_t aNewProt) + : mMMPolicy(aMMPolicy) + { + const uint32_t pageSize = MMPolicy::GetPageSize(); + const uintptr_t limit = aAddr + aNumBytes - 1; + const uintptr_t limitPageNum = limit / pageSize; + const uintptr_t basePageNum = aAddr / pageSize; + const uintptr_t numPagesToChange = limitPageNum - basePageNum + 1; + + // We'll use the base address of the page instead of aAddr + uintptr_t curAddr = basePageNum * pageSize; + + // Now change the protection on each page + for (uintptr_t curPage = 0; curPage < numPagesToChange; + ++curPage, curAddr += pageSize) { + uint32_t prevProt; + if (!aMMPolicy.Protect(reinterpret_cast(curAddr), pageSize, + aNewProt, &prevProt)) { + Clear(); + return; + } + + // Save the previous protection for curAddr so that we can revert this + // in the destructor. + if (!mProtects.append(MakeTuple(curAddr, prevProt))) { + Clear(); + return; + } + } + } + + AutoProtect(AutoProtect&& aOther) + : mMMPolicy(aOther.mMMPolicy) + , mProtects(std::move(aOther.mProtects)) + { + aOther.mProtects.clear(); + } + + ~AutoProtect() + { + Clear(); + } + + explicit operator bool() const + { + return !mProtects.empty(); + } + + AutoProtect(const AutoProtect&) = delete; + AutoProtect& operator=(const AutoProtect&) = delete; + AutoProtect& operator=(AutoProtect&&) = delete; + + private: + void Clear() + { + const uint32_t pageSize = MMPolicy::GetPageSize(); + for (auto&& entry : mProtects) { + uint32_t prevProt; + DebugOnly ok = + mMMPolicy.Protect(reinterpret_cast(Get<0>(entry)), pageSize, + Get<1>(entry), &prevProt); + MOZ_ASSERT(ok); + } + + mProtects.clear(); + } + + private: + const MMPolicy& mMMPolicy; + // We include two entries of inline storage as that is most common in the + // worst case. + Vector mProtects; + }; + public: /** * Used to initialize an invalid WritableTargetFunction, thus signalling an error. @@ -30,8 +117,8 @@ public: , mNumBytes(0) , mOffset(0) , mStartWriteOffset(0) - , mPrevProt(0) , mAccumulatedStatus(false) + , mProtect(aMMPolicy) { } @@ -42,11 +129,9 @@ public: , mNumBytes(aNumBytes) , mOffset(0) , mStartWriteOffset(0) - , mPrevProt(0) , mAccumulatedStatus(true) + , mProtect(aMMPolicy, aFunc, aNumBytes, PAGE_EXECUTE_READWRITE) { - aMMPolicy.Protect(reinterpret_cast(aFunc), aNumBytes, - PAGE_EXECUTE_READWRITE, &mPrevProt); } WritableTargetFunction(WritableTargetFunction&& aOther) @@ -55,25 +140,16 @@ public: , mNumBytes(aOther.mNumBytes) , mOffset(aOther.mOffset) , mStartWriteOffset(aOther.mStartWriteOffset) - , mPrevProt(aOther.mPrevProt) , mLocalBytes(std::move(aOther.mLocalBytes)) , mAccumulatedStatus(aOther.mAccumulatedStatus) + , mProtect(std::move(aOther.mProtect)) { - aOther.mPrevProt = 0; aOther.mAccumulatedStatus = false; } ~WritableTargetFunction() { - if (!mPrevProt) { - return; - } - MOZ_ASSERT(mLocalBytes.empty(), "Did you forget to call Commit?"); - - DebugOnly ok = mMMPolicy.Protect(reinterpret_cast(mFunc), - mNumBytes, mPrevProt, &mPrevProt); - MOZ_ASSERT(ok); } WritableTargetFunction(const WritableTargetFunction&) = delete; @@ -107,7 +183,7 @@ public: explicit operator bool() const { - return mPrevProt && mAccumulatedStatus; + return mProtect && mAccumulatedStatus; } void WriteByte(const uint8_t& aValue) @@ -225,7 +301,6 @@ private: const size_t mNumBytes; uint32_t mOffset; uint32_t mStartWriteOffset; - uint32_t mPrevProt; // In an ideal world, we'd only read 5 bytes on 32-bit and 13 bytes on 64-bit, // to match the minimum bytes that we need to write in in order to patch the @@ -240,6 +315,7 @@ private: #endif Vector mLocalBytes; bool mAccumulatedStatus; + AutoProtect mProtect; }; template From ad2647f459092154f0c42590428488edf3c54e6b Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 24 May 2018 14:44:09 +0100 Subject: [PATCH 088/116] Bug 1463115 - Try to skip irrelevant (collapsed/trimmed) whitespace when collecting used font faces for devtools inspector. r=jwatt --- dom/base/nsRange.cpp | 11 ++++++---- dom/base/nsRange.h | 3 ++- dom/chrome-webidl/InspectorUtils.webidl | 3 ++- layout/base/nsLayoutUtils.cpp | 28 +++++++++++++++++-------- layout/base/nsLayoutUtils.h | 6 ++++-- layout/generic/nsTextFrame.cpp | 6 +++++- layout/generic/nsTextFrame.h | 4 ++-- layout/inspector/InspectorUtils.cpp | 4 +++- layout/inspector/InspectorUtils.h | 1 + 9 files changed, 45 insertions(+), 21 deletions(-) diff --git a/dom/base/nsRange.cpp b/dom/base/nsRange.cpp index 5a4f46da60f0..cde28563c486 100644 --- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3157,7 +3157,7 @@ nsRange::GetClientRectsAndTexts( nsresult nsRange::GetUsedFontFaces(nsTArray>& aResult, - uint32_t aMaxRanges) + uint32_t aMaxRanges, bool aSkipCollapsedWhitespace) { NS_ENSURE_TRUE(mStart.Container(), NS_ERROR_UNEXPECTED); @@ -3201,17 +3201,20 @@ nsRange::GetUsedFontFaces(nsTArray>& aResult, int32_t offset = startContainer == endContainer ? mEnd.Offset() : content->GetText()->GetLength(); nsLayoutUtils::GetFontFacesForText(frame, mStart.Offset(), offset, - true, fontFaces, aMaxRanges); + true, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); continue; } if (node == endContainer) { nsLayoutUtils::GetFontFacesForText(frame, 0, mEnd.Offset(), - true, fontFaces, aMaxRanges); + true, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); continue; } } - nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges); + nsLayoutUtils::GetFontFacesForFrames(frame, fontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } // Take ownership of the InspectorFontFaces in the table and move them into diff --git a/dom/base/nsRange.h b/dom/base/nsRange.h index 5e2bae621be2..f0ee5496e91d 100644 --- a/dom/base/nsRange.h +++ b/dom/base/nsRange.h @@ -270,7 +270,8 @@ public: // where each face was used). nsresult GetUsedFontFaces( nsTArray>& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); // nsIMutationObserver methods NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED diff --git a/dom/chrome-webidl/InspectorUtils.webidl b/dom/chrome-webidl/InspectorUtils.webidl index a38508e16b8c..0ab6a0ba6ea3 100644 --- a/dom/chrome-webidl/InspectorUtils.webidl +++ b/dom/chrome-webidl/InspectorUtils.webidl @@ -65,7 +65,8 @@ namespace InspectorUtils { // to access via its .ranges attribute. [NewObject, Throws] sequence getUsedFontFaces( Range range, - optional unsigned long maxRanges = 0); + optional unsigned long maxRanges = 0, + optional boolean skipCollapsedWhitespace = true); sequence getCSSPseudoElementNames(); void addPseudoClassLock(Element element, diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 7fabbc6bc403..304d18324535 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -7864,14 +7864,16 @@ nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(nsIFrame *aSubtreeRoot) static void GetFontFacesForFramesInner(nsIFrame* aFrame, nsLayoutUtils::UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); if (aFrame->IsTextFrame()) { if (!aFrame->GetPrevContinuation()) { nsLayoutUtils::GetFontFacesForText(aFrame, 0, INT32_MAX, true, - aFontFaces, aMaxRanges); + aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } return; } @@ -7883,7 +7885,8 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) { nsIFrame* child = e.get(); child = nsPlaceholderFrame::GetRealFrameFor(child); - GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges); + GetFontFacesForFramesInner(child, aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); } } } @@ -7891,12 +7894,14 @@ GetFontFacesForFramesInner(nsIFrame* aFrame, /* static */ nsresult nsLayoutUtils::GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); while (aFrame) { - GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges); + GetFontFacesForFramesInner(aFrame, aFontFaces, aMaxRanges, + aSkipCollapsedWhitespace); aFrame = GetNextContinuationOrIBSplitSibling(aFrame); } @@ -7967,7 +7972,8 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aFontFaces, - uint32_t aMaxRanges) + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace) { MOZ_ASSERT(aFrame, "NULL frame pointer"); @@ -8007,9 +8013,13 @@ nsLayoutUtils::GetFontFacesForText(nsIFrame* aFrame, } } - gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), - iter.ConvertOriginalToSkipped(fend)); - AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); + if (!aSkipCollapsedWhitespace || + (curr->HasAnyNoncollapsedCharacters() && + curr->HasNonSuppressedText())) { + gfxTextRun::Range range(iter.ConvertOriginalToSkipped(fstart), + iter.ConvertOriginalToSkipped(fend)); + AddFontsFromTextRun(textRun, curr, iter, range, aFontFaces, aMaxRanges); + } curr = next; } while (aFollowContinuations && curr); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 2675847487e8..3a4ad0c9dff9 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -2288,7 +2288,8 @@ public: */ static nsresult GetFontFacesForFrames(nsIFrame* aFrame, UsedFontFaceTable& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); /** * Adds all font faces used within the specified range of text in aFrame, @@ -2302,7 +2303,8 @@ public: int32_t aEndOffset, bool aFollowContinuations, UsedFontFaceTable& aResult, - uint32_t aMaxRanges); + uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace); /** * Walks the frame tree starting at aFrame looking for textRuns. diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 328839df4926..721332d357ce 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -10420,7 +10420,11 @@ nsTextFrame::CountGraphemeClusters() const bool nsTextFrame::HasNonSuppressedText() { - if (HasAnyStateBits(TEXT_ISNOT_ONLY_WHITESPACE)) { + if (HasAnyStateBits(TEXT_ISNOT_ONLY_WHITESPACE | + // If we haven't reflowed yet, or are currently doing so, + // just return true because we can't be sure. + NS_FRAME_FIRST_REFLOW | + NS_FRAME_IN_REFLOW)) { return true; } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 92754a7a92ad..af0a9ab14a81 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -666,6 +666,8 @@ public: uint32_t CountGraphemeClusters() const; + bool HasAnyNoncollapsedCharacters() override; + protected: virtual ~nsTextFrame(); @@ -882,8 +884,6 @@ protected: void ClearFrameOffsetCache(); - bool HasAnyNoncollapsedCharacters() override; - void ClearMetrics(ReflowOutput& aMetrics); /** diff --git a/layout/inspector/InspectorUtils.cpp b/layout/inspector/InspectorUtils.cpp index 9cef97b5a361..cc09fe684b85 100644 --- a/layout/inspector/InspectorUtils.cpp +++ b/layout/inspector/InspectorUtils.cpp @@ -617,10 +617,12 @@ InspectorUtils::GetCleanComputedStyleForElement(dom::Element* aElement, InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject, nsRange& aRange, uint32_t aMaxRanges, + bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv) { - nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges); + nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges, + aSkipCollapsedWhitespace); if (NS_FAILED(rv)) { aRv.Throw(rv); } diff --git a/layout/inspector/InspectorUtils.h b/layout/inspector/InspectorUtils.h index 8efa267b8f42..0c3f8ec09d55 100644 --- a/layout/inspector/InspectorUtils.h +++ b/layout/inspector/InspectorUtils.h @@ -225,6 +225,7 @@ public: nsRange& aRange, uint32_t aMaxRanges, // max number of ranges to // record for each face + bool aSkipCollapsedWhitespace, nsTArray>& aResult, ErrorResult& aRv); From c7f378d7ab98a2e69557e7d1c2411f2c228dbe6f Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 22:35:22 -0400 Subject: [PATCH 089/116] Bug 1465875 part 1. Eliminate pointless QIs to nsIDOMNSEditableElement. r=qdot We expose the relevant APIs on textarea and input elements anyway (chromeonly). The QIs will throw on a non-input or non-textarea element, but none of these consumers expect that to happen. --- .../mochitest/events/test_textattrchange.html | 5 +---- browser/base/content/nsContextMenu.js | 2 +- .../mochitest/chrome/queryCaretRectUnix.html | 7 ++----- .../mochitest/chrome/queryCaretRectWin.html | 7 ++----- editor/libeditor/tests/test_bug1053048.html | 3 +-- editor/libeditor/tests/test_bug1230473.html | 1 - editor/libeditor/tests/test_bug471319.html | 2 -- editor/libeditor/tests/test_bug602130.html | 1 - editor/libeditor/tests/test_bug830600.html | 1 - ...est_composition_event_created_in_chrome.html | 3 +-- editor/spellchecker/tests/test_bug1200533.html | 2 +- editor/spellchecker/tests/test_bug1204147.html | 2 +- editor/spellchecker/tests/test_bug1205983.html | 1 - editor/spellchecker/tests/test_bug1209414.html | 3 +-- editor/spellchecker/tests/test_bug678842.html | 2 +- editor/spellchecker/tests/test_bug697981.html | 4 ++-- editor/spellchecker/tests/test_bug717433.html | 2 +- layout/base/tests/bug585922-ref.html | 2 +- layout/base/tests/bug585922.html | 2 +- layout/base/tests/chrome/test_bug504311.xul | 2 +- layout/forms/test/bug477700_subframe.html | 4 ++-- layout/forms/test/test_bug595310.html | 1 - .../test/test_selection_preventDefault.html | 5 +---- mobile/android/modules/ActionBarHandler.jsm | 17 +++++++++++++---- mobile/android/modules/FormAssistant.jsm | 7 +++---- .../tests/browser/robocop/robocop_input.html | 6 ++---- toolkit/content/widgets/menulist.xml | 3 +-- toolkit/content/widgets/textbox.xml | 3 +-- toolkit/modules/InlineSpellCheckerContent.jsm | 2 +- .../window_composition_text_querycontent.xul | 3 +-- 30 files changed, 43 insertions(+), 62 deletions(-) diff --git a/accessible/tests/mochitest/events/test_textattrchange.html b/accessible/tests/mochitest/events/test_textattrchange.html index 53b4a9981b43..9001ed685cb1 100644 --- a/accessible/tests/mochitest/events/test_textattrchange.html +++ b/accessible/tests/mochitest/events/test_textattrchange.html @@ -24,9 +24,6 @@ diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index b1508ea90a3e..3b14ad91d8ed 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -354,6 +354,12 @@ HTMLTextAreaElement::SetValue(const nsAString& aValue, ErrorResult& aError) } } +void HTMLTextAreaElement::SetUserInput(const nsAString& aValue, + nsIPrincipal& aSubjectPrincipal) +{ + SetUserInput(aValue); +} + NS_IMETHODIMP HTMLTextAreaElement::SetUserInput(const nsAString& aValue) { diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h index 395caaccbe0f..5aa94e35581a 100644 --- a/dom/html/HTMLTextAreaElement.h +++ b/dom/html/HTMLTextAreaElement.h @@ -315,6 +315,9 @@ public: return mState.GetTextEditor(); } + void SetUserInput(const nsAString& aValue, + nsIPrincipal& aSubjectPrincipal); + protected: virtual ~HTMLTextAreaElement() {} diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index 44b0011c73c3..c5f4ab8a533e 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -187,10 +187,8 @@ partial interface HTMLInputElement { AutocompleteInfo? getAutocompleteInfo(); }; -partial interface HTMLInputElement { - // Mirrored chrome-only nsIDOMNSEditableElement methods. Please make sure - // to update this list if nsIDOMNSEditableElement changes. - +[NoInterfaceObject] +interface MozEditableElement { [Pure, ChromeOnly] readonly attribute nsIEditor? editor; @@ -201,6 +199,8 @@ partial interface HTMLInputElement { void setUserInput(DOMString input); }; +HTMLInputElement implements MozEditableElement; + partial interface HTMLInputElement { [Pref="dom.input.dirpicker", SetterThrows] attribute boolean allowdirs; diff --git a/dom/webidl/HTMLTextAreaElement.webidl b/dom/webidl/HTMLTextAreaElement.webidl index f063e9840059..026007e1c0ca 100644 --- a/dom/webidl/HTMLTextAreaElement.webidl +++ b/dom/webidl/HTMLTextAreaElement.webidl @@ -85,20 +85,7 @@ partial interface HTMLTextAreaElement { readonly attribute XULControllers controllers; }; -partial interface HTMLTextAreaElement { - // Mirrored chrome-only nsIDOMNSEditableElement methods. Please make sure - // to update this list if nsIDOMNSEditableElement changes. - - [ChromeOnly] - readonly attribute nsIEditor? editor; - - // This is similar to set .value on nsIDOMInput/TextAreaElements, but - // handling of the value change is closer to the normal user input, so - // 'change' event for example will be dispatched when focusing out the - // element. - [ChromeOnly] - void setUserInput(DOMString input); -}; +HTMLTextAreaElement implements MozEditableElement; partial interface HTMLTextAreaElement { [ChromeOnly] diff --git a/editor/libeditor/tests/test_texteditor_keyevent_handling.html b/editor/libeditor/tests/test_texteditor_keyevent_handling.html index 581321e0d931..903f56d95715 100644 --- a/editor/libeditor/tests/test_texteditor_keyevent_handling.html +++ b/editor/libeditor/tests/test_texteditor_keyevent_handling.html @@ -360,7 +360,6 @@ function runTests() // make non-tabbable plaintext editor textarea.removeAttribute("readonly"); const nsIPlaintextEditor = SpecialPowers.Ci.nsIPlaintextEditor; - const nsIDOMNSEditableElement = SpecialPowers.Ci.nsIDOMNSEditableElement; var editor = SpecialPowers.wrap(textarea).editor; var flags = editor.flags; editor.flags = flags & ~(nsIPlaintextEditor.eEditorWidgetMask | diff --git a/layout/generic/test/test_selection_expanding.html b/layout/generic/test/test_selection_expanding.html index 7d6bea81b455..c5bcf29bade8 100644 --- a/layout/generic/test/test_selection_expanding.html +++ b/layout/generic/test/test_selection_expanding.html @@ -81,7 +81,6 @@ function test() { function getSelectionForEditor(aEditorElement) { - const nsIDOMNSEditableElement = SpecialPowers.Ci.nsIDOMNSEditableElement; return SpecialPowers.wrap(aEditorElement).editor.selection; } diff --git a/toolkit/content/tests/chrome/findbar_window.xul b/toolkit/content/tests/chrome/findbar_window.xul index c0ae554f6cdb..f0d896ec9e85 100644 --- a/toolkit/content/tests/chrome/findbar_window.xul +++ b/toolkit/content/tests/chrome/findbar_window.xul @@ -181,7 +181,7 @@ await openFindbar(); checkFindbarState("plain text", SEARCH_TEXT); - // Test nsIDOMNSEditableElement with selection. + // Test editable element with selection. await ContentTask.spawn(gBrowser, null, async function() { let textInput = content.document.getElementById("text"); textInput.focus(); @@ -190,7 +190,7 @@ await openFindbar(); checkFindbarState("text input", SAMPLE_TEXT); - // Test non-editable nsIDOMNSEditableElement (button). + // Test non-editable input element (type="button"). await ContentTask.spawn(gBrowser, null, async function() { content.document.getElementById("button").focus(); }); From 640e7f711247253477b29345db9a5bf5597be8e2 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 22:35:23 -0400 Subject: [PATCH 093/116] Bug 1465875 part 5. Eliminate nsIDOMNSEditableElement. r=qdot --- dom/html/HTMLInputElement.cpp | 33 +++++++------------ dom/html/HTMLInputElement.h | 12 ------- dom/html/HTMLTextAreaElement.cpp | 9 +---- dom/html/HTMLTextAreaElement.h | 11 ------- dom/html/test/test_bug389797.html | 15 ++------- dom/interfaces/core/moz.build | 15 --------- .../core/nsIDOMNSEditableElement.idl | 28 ---------------- dom/moz.build | 1 - .../satchel/nsFormFillController.cpp | 3 +- 9 files changed, 16 insertions(+), 111 deletions(-) delete mode 100644 dom/interfaces/core/moz.build delete mode 100644 dom/interfaces/core/nsIDOMNSEditableElement.idl diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 7b463b5af0e7..e4c3d11aa895 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -22,7 +22,6 @@ #include "nsQueryObject.h" #include "nsITextControlElement.h" -#include "nsIDOMNSEditableElement.h" #include "nsIRadioVisitor.h" #include "InputType.h" @@ -1119,7 +1118,6 @@ NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLInputElement, nsITextControlElement, imgINotificationObserver, nsIImageLoadingContent, - nsIDOMNSEditableElement, nsIConstraintValidation) // nsINode @@ -2342,38 +2340,31 @@ HTMLInputElement::GetOwnerNumberControl() } void -HTMLInputElement::SetUserInput(const nsAString& aInput, +HTMLInputElement::SetUserInput(const nsAString& aValue, nsIPrincipal& aSubjectPrincipal) { if (mType == NS_FORM_INPUT_FILE && !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) { return; } - SetUserInput(aInput); -} - -NS_IMETHODIMP -HTMLInputElement::SetUserInput(const nsAString& aValue) -{ if (mType == NS_FORM_INPUT_FILE) { Sequence list; if (!list.AppendElement(aValue, fallible)) { - return NS_ERROR_OUT_OF_MEMORY; + return; } - ErrorResult rv; - MozSetFileNameArray(list, rv); - return rv.StealNSResult(); - } else { - nsresult rv = - SetValueInternal(aValue, - nsTextEditorState::eSetValue_BySetUserInput | - nsTextEditorState::eSetValue_Notify| - nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged); - NS_ENSURE_SUCCESS(rv, rv); + MozSetFileNameArray(list, IgnoreErrors()); + return; } + nsresult rv = + SetValueInternal(aValue, + nsTextEditorState::eSetValue_BySetUserInput | + nsTextEditorState::eSetValue_Notify| + nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged); + NS_ENSURE_SUCCESS_VOID(rv); + nsContentUtils::DispatchTrustedEvent(OwnerDoc(), static_cast(this), NS_LITERAL_STRING("input"), true, @@ -2384,8 +2375,6 @@ HTMLInputElement::SetUserInput(const nsAString& aValue) if (!ShouldBlur(this)) { FireChangeEventIfNeeded(); } - - return NS_OK; } nsIEditor* diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index b1facc2e9377..5689efe3766b 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -12,7 +12,6 @@ #include "nsImageLoadingContent.h" #include "nsITextControlElement.h" #include "nsITimer.h" -#include "nsIDOMNSEditableElement.h" #include "nsCOMPtr.h" #include "nsIConstraintValidation.h" #include "mozilla/UniquePtr.h" @@ -125,7 +124,6 @@ public: class HTMLInputElement final : public nsGenericHTMLFormElementWithState, public nsImageLoadingContent, public nsITextControlElement, - public nsIDOMNSEditableElement, public nsIConstraintValidation { friend class AfterSetFilesOrDirectoriesCallback; @@ -164,16 +162,6 @@ public: // EventTarget virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override; - // nsIDOMNSEditableElement - NS_IMETHOD GetEditor(nsIEditor** aEditor) override - { - nsCOMPtr editor = GetEditor(); - editor.forget(aEditor); - return NS_OK; - } - - NS_IMETHOD SetUserInput(const nsAString& aInput) override; - // Overriden nsIFormControl methods NS_IMETHOD Reset() override; NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override; diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index 3b14ad91d8ed..ce4eafd443df 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -87,7 +87,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement, NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(HTMLTextAreaElement, nsGenericHTMLFormElementWithState, nsITextControlElement, - nsIDOMNSEditableElement, nsIMutationObserver, nsIConstraintValidation) @@ -357,13 +356,7 @@ HTMLTextAreaElement::SetValue(const nsAString& aValue, ErrorResult& aError) void HTMLTextAreaElement::SetUserInput(const nsAString& aValue, nsIPrincipal& aSubjectPrincipal) { - SetUserInput(aValue); -} - -NS_IMETHODIMP -HTMLTextAreaElement::SetUserInput(const nsAString& aValue) -{ - return SetValueInternal(aValue, + SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput | nsTextEditorState::eSetValue_Notify| nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged); diff --git a/dom/html/HTMLTextAreaElement.h b/dom/html/HTMLTextAreaElement.h index 5aa94e35581a..26c3a01ad3ef 100644 --- a/dom/html/HTMLTextAreaElement.h +++ b/dom/html/HTMLTextAreaElement.h @@ -10,7 +10,6 @@ #include "mozilla/Attributes.h" #include "nsITextControlElement.h" #include "nsIControllers.h" -#include "nsIDOMNSEditableElement.h" #include "nsCOMPtr.h" #include "nsGenericHTMLElement.h" #include "nsStubMutationObserver.h" @@ -39,7 +38,6 @@ class HTMLFormSubmission; class HTMLTextAreaElement final : public nsGenericHTMLFormElementWithState, public nsITextControlElement, - public nsIDOMNSEditableElement, public nsStubMutationObserver, public nsIConstraintValidation { @@ -62,15 +60,6 @@ public: return true; } - // nsIDOMNSEditableElement - NS_IMETHOD GetEditor(nsIEditor** aEditor) override - { - nsCOMPtr editor = GetEditor(); - editor.forget(aEditor); - return NS_OK; - } - NS_IMETHOD SetUserInput(const nsAString& aInput) override; - // nsIFormControl NS_IMETHOD Reset() override; NS_IMETHOD SubmitNamesValues(HTMLFormSubmission* aFormSubmission) override; diff --git a/dom/html/test/test_bug389797.html b/dom/html/test/test_bug389797.html index c8934d3c3d9a..7b90efc6ab4a 100644 --- a/dom/html/test/test_bug389797.html +++ b/dom/html/test/test_bug389797.html @@ -36,16 +36,6 @@ function HTML_TAG(aTagName, aImplClass) { // inherit from them do. interfacesNonClassinfo[aTagName] = [ ]; - var interfaceName = "nsIDOM" + getClassName(aTagName); - if (interfaceName in SpecialPowers.Ci) { // no nsIDOMHTMLSpanElement - interfaces[aTagName].push(interfaceName); - } - - var interfaceNameNS = "nsIDOMNS" + getClassName(aTagName); - if (interfaceNameNS in SpecialPowers.Ci) { - interfaces[aTagName].push(interfaceNameNS); - } - if (arguments.length > 2) { for (var i = 0; i < arguments[2].length; ++i) { interfaces[aTagName].push(arguments[2][i]); @@ -148,8 +138,7 @@ HTML_TAG("iframe", "IFrame", [ "nsIDOMMozBrowserFrame" ], HTML_TAG("image", ""); HTML_TAG("img", "Image", [ "nsIImageLoadingContent" ], []); HTML_TAG("input", "Input", [], [ "imgINotificationObserver", - "nsIImageLoadingContent", - "nsIDOMNSEditableElement" ]); + "nsIImageLoadingContent" ]); HTML_TAG("ins", "Mod"); HTML_TAG("kbd", ""); HTML_TAG("keygen", "Span"); @@ -201,7 +190,7 @@ HTML_TAG("sup", ""); HTML_TAG("table", "Table"); HTML_TAG("tbody", "TableSection"); HTML_TAG("td", "TableCell"); -HTML_TAG("textarea", "TextArea", [], [ "nsIDOMNSEditableElement" ]); +HTML_TAG("textarea", "TextArea"); HTML_TAG("tfoot", "TableSection"); HTML_TAG("th", "TableCell"); HTML_TAG("thead", "TableSection"); diff --git a/dom/interfaces/core/moz.build b/dom/interfaces/core/moz.build deleted file mode 100644 index 6a8f60dae4f0..000000000000 --- a/dom/interfaces/core/moz.build +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -with Files("**"): - BUG_COMPONENT = ("Core", "DOM") - -XPIDL_SOURCES += [ - 'nsIDOMNSEditableElement.idl', -] - -XPIDL_MODULE = 'dom_core' - diff --git a/dom/interfaces/core/nsIDOMNSEditableElement.idl b/dom/interfaces/core/nsIDOMNSEditableElement.idl deleted file mode 100644 index 67cb10488ba8..000000000000 --- a/dom/interfaces/core/nsIDOMNSEditableElement.idl +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: IDL; 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 nsIEditor; - -/** - * This interface is implemented by elements which have inner editable content, - * such as HTML input and textarea. - * - * Please make sure to update the HTMLTextAreaElement and HTMLInputElement - * Web IDL interfaces to mirror this interface when changing it. - * - */ - -[scriptable, uuid(3503de34-6631-4594-b7be-c36ff6a520c4)] -interface nsIDOMNSEditableElement : nsISupports -{ - [noscript] readonly attribute nsIEditor editor; - // This is similar to set .value on nsIDOMInput/TextAreaElements, but - // handling of the value change is closer to the normal user input, so - // 'change' event for example will be dispatched when focusing out the - // element. - [noscript] void setUserInput(in DOMString input); -}; diff --git a/dom/moz.build b/dom/moz.build index 30d5a4450fa5..4493c851ef34 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -15,7 +15,6 @@ JAR_MANIFESTS += ['jar.mn'] interfaces = [ 'base', - 'core', 'html', 'events', 'sidebar', diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index a9d2c08c908e..0d0a28f0758b 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -578,7 +578,8 @@ nsFormFillController::SetTextValue(const nsAString & aTextValue) { if (mFocusedInput) { mSuppressOnInput = true; - mFocusedInput->SetUserInput(aTextValue); + mFocusedInput->SetUserInput(aTextValue, + *nsContentUtils::GetSystemPrincipal()); mSuppressOnInput = false; } From bddc220e1b89fee632a16cb5c02e534a6ea4e502 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 22:35:26 -0400 Subject: [PATCH 094/116] Bug 1466253. HTMLFieldSetElement::GetType should return void. r=qdot --- dom/html/HTMLFieldSetElement.cpp | 5 ++--- dom/html/HTMLFieldSetElement.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dom/html/HTMLFieldSetElement.cpp b/dom/html/HTMLFieldSetElement.cpp index 5eebebdc0204..fd50146f5e28 100644 --- a/dom/html/HTMLFieldSetElement.cpp +++ b/dom/html/HTMLFieldSetElement.cpp @@ -98,11 +98,10 @@ HTMLFieldSetElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName, aSubjectPrincipal, aNotify); } -NS_IMETHODIMP -HTMLFieldSetElement::GetType(nsAString& aType) +void +HTMLFieldSetElement::GetType(nsAString& aType) const { aType.AssignLiteral("fieldset"); - return NS_OK; } /* static */ diff --git a/dom/html/HTMLFieldSetElement.h b/dom/html/HTMLFieldSetElement.h index 1cf7c411a969..a9d98608aa24 100644 --- a/dom/html/HTMLFieldSetElement.h +++ b/dom/html/HTMLFieldSetElement.h @@ -83,7 +83,7 @@ public: SetHTMLAttr(nsGkAtoms::name, aValue, aRv); } - NS_IMETHOD GetType(nsAString & aType); + void GetType(nsAString & aType) const; nsIHTMLCollection* Elements(); From 01f73b98d92554eaa595841f6abf18d339256dea Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 22:35:42 -0400 Subject: [PATCH 095/116] Bug 1466213 part 1. Move PositionError out into a separate file. r=qdot --HG-- rename : dom/geolocation/nsGeolocation.cpp => dom/geolocation/PositionError.cpp rename : dom/geolocation/nsGeolocation.h => dom/geolocation/PositionError.h --- dom/bindings/Bindings.conf | 4 -- dom/geolocation/PositionError.cpp | 93 +++++++++++++++++++++++++++++++ dom/geolocation/PositionError.h | 53 ++++++++++++++++++ dom/geolocation/moz.build | 5 ++ dom/geolocation/nsGeolocation.cpp | 82 +-------------------------- dom/geolocation/nsGeolocation.h | 28 ---------- 6 files changed, 153 insertions(+), 112 deletions(-) create mode 100644 dom/geolocation/PositionError.cpp create mode 100644 dom/geolocation/PositionError.h diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index a02ce129af53..56827ee6db59 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -683,10 +683,6 @@ DOMInterfaces = { 'headerFile': 'nsGeoPosition.h' }, -'PositionError': { - 'headerFile': 'nsGeolocation.h' -}, - 'PromiseDebugging': { 'concrete': False, }, diff --git a/dom/geolocation/PositionError.cpp b/dom/geolocation/PositionError.cpp new file mode 100644 index 000000000000..38698fffeee3 --- /dev/null +++ b/dom/geolocation/PositionError.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "mozilla/dom/PositionError.h" +#include "mozilla/dom/PositionErrorBinding.h" +#include "nsGeolocation.h" + +namespace mozilla { +namespace dom { + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError) + NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent) +NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError) +NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError) + +PositionError::PositionError(Geolocation* aParent, int16_t aCode) + : mCode(aCode) + , mParent(aParent) +{ +} + +PositionError::~PositionError() = default; + + +NS_IMETHODIMP +PositionError::GetCode(int16_t *aCode) +{ + NS_ENSURE_ARG_POINTER(aCode); + *aCode = Code(); + return NS_OK; +} + +NS_IMETHODIMP +PositionError::GetMessage(nsAString& aMessage) +{ + switch (mCode) + { + case nsIDOMGeoPositionError::PERMISSION_DENIED: + aMessage = NS_LITERAL_STRING("User denied geolocation prompt"); + break; + case nsIDOMGeoPositionError::POSITION_UNAVAILABLE: + aMessage = NS_LITERAL_STRING("Unknown error acquiring position"); + break; + case nsIDOMGeoPositionError::TIMEOUT: + aMessage = NS_LITERAL_STRING("Position acquisition timed out"); + break; + default: + break; + } + return NS_OK; +} + +nsWrapperCache* +PositionError::GetParentObject() const +{ + return mParent; +} + +JSObject* +PositionError::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PositionErrorBinding::Wrap(aCx, this, aGivenProto); +} + +void +PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) +{ + nsAutoMicroTask mt; + if (aCallback.HasWebIDLCallback()) { + PositionErrorCallback* callback = aCallback.GetWebIDLCallback(); + + if (callback) { + callback->Call(*this); + } + } else { + nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback(); + if (callback) { + callback->HandleEvent(this); + } + } +} + +} // namespace mozilla +} // namespace dom + diff --git a/dom/geolocation/PositionError.h b/dom/geolocation/PositionError.h new file mode 100644 index 000000000000..0ffa09b376fd --- /dev/null +++ b/dom/geolocation/PositionError.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef mozilla_dom_PositionError_h +#define mozilla_dom_PositionError_h + +#include "nsIDOMGeoPositionError.h" +#include "nsWrapperCache.h" +#include "nsISupportsImpl.h" +#include "nsCycleCollectionParticipant.h" +#include "mozilla/dom/CallbackObject.h" + +class nsIDOMGeoPositionErrorCallback; + +namespace mozilla { +namespace dom { +class PositionErrorCallback; +class Geolocation; +typedef CallbackObjectHolder GeoPositionErrorCallback; + +class PositionError final : public nsIDOMGeoPositionError, + public nsWrapperCache +{ +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PositionError) + + NS_DECL_NSIDOMGEOPOSITIONERROR + + PositionError(Geolocation* aParent, int16_t aCode); + + nsWrapperCache* GetParentObject() const; + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + int16_t Code() const { + return mCode; + } + + void NotifyCallback(const GeoPositionErrorCallback& callback); +private: + ~PositionError(); + int16_t mCode; + RefPtr mParent; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_PositionError_h */ diff --git a/dom/geolocation/moz.build b/dom/geolocation/moz.build index 86b9d2d4fb57..b7c959f08194 100644 --- a/dom/geolocation/moz.build +++ b/dom/geolocation/moz.build @@ -12,8 +12,13 @@ EXPORTS += [ 'nsGeoPositionIPCSerialiser.h', ] +EXPORTS.mozilla.dom += [ + 'PositionError.h', +] + SOURCES += [ 'nsGeolocation.cpp', + 'PositionError.cpp', ] UNIFIED_SOURCES += [ diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp index 1769db669715..4154da993ad5 100644 --- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -9,6 +9,7 @@ #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/PositionError.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" @@ -21,6 +22,7 @@ #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsIDocument.h" +#include "nsIDOMGeoPositionError.h" #include "nsINamed.h" #include "nsIObserverService.h" #include "nsIScriptError.h" @@ -219,86 +221,6 @@ private: RefPtr mLocator; }; -//////////////////////////////////////////////////// -// PositionError -//////////////////////////////////////////////////// - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError) - NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent) -NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError) -NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError) - -PositionError::PositionError(Geolocation* aParent, int16_t aCode) - : mCode(aCode) - , mParent(aParent) -{ -} - -PositionError::~PositionError() = default; - - -NS_IMETHODIMP -PositionError::GetCode(int16_t *aCode) -{ - NS_ENSURE_ARG_POINTER(aCode); - *aCode = Code(); - return NS_OK; -} - -NS_IMETHODIMP -PositionError::GetMessage(nsAString& aMessage) -{ - switch (mCode) - { - case nsIDOMGeoPositionError::PERMISSION_DENIED: - aMessage = NS_LITERAL_STRING("User denied geolocation prompt"); - break; - case nsIDOMGeoPositionError::POSITION_UNAVAILABLE: - aMessage = NS_LITERAL_STRING("Unknown error acquiring position"); - break; - case nsIDOMGeoPositionError::TIMEOUT: - aMessage = NS_LITERAL_STRING("Position acquisition timed out"); - break; - default: - break; - } - return NS_OK; -} - -Geolocation* -PositionError::GetParentObject() const -{ - return mParent; -} - -JSObject* -PositionError::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return PositionErrorBinding::Wrap(aCx, this, aGivenProto); -} - -void -PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) -{ - nsAutoMicroTask mt; - if (aCallback.HasWebIDLCallback()) { - PositionErrorCallback* callback = aCallback.GetWebIDLCallback(); - - if (callback) { - callback->Call(*this); - } - } else { - nsIDOMGeoPositionErrorCallback* callback = aCallback.GetXPCOMCallback(); - if (callback) { - callback->HandleEvent(this); - } - } -} //////////////////////////////////////////////////// // nsGeolocationRequest //////////////////////////////////////////////////// diff --git a/dom/geolocation/nsGeolocation.h b/dom/geolocation/nsGeolocation.h index c412cb3f8a01..909700da17df 100644 --- a/dom/geolocation/nsGeolocation.h +++ b/dom/geolocation/nsGeolocation.h @@ -23,12 +23,10 @@ #include "nsGeoPosition.h" #include "nsIDOMGeoGeolocation.h" #include "nsIDOMGeoPosition.h" -#include "nsIDOMGeoPositionError.h" #include "nsIDOMGeoPositionCallback.h" #include "nsIDOMGeoPositionErrorCallback.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/GeolocationBinding.h" -#include "mozilla/dom/PositionErrorBinding.h" #include "mozilla/dom/CallbackObject.h" #include "nsIGeolocationProvider.h" @@ -237,32 +235,6 @@ private: nsTArray mClearedWatchIDs; }; -class PositionError final : public nsIDOMGeoPositionError, - public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PositionError) - - NS_DECL_NSIDOMGEOPOSITIONERROR - - PositionError(Geolocation* aParent, int16_t aCode); - - Geolocation* GetParentObject() const; - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - - int16_t Code() const { - return mCode; - } - - void NotifyCallback(const GeoPositionErrorCallback& callback); -private: - ~PositionError(); - int16_t mCode; - RefPtr mParent; -}; - } // namespace dom inline nsISupports* From c53f7f15b117ff996322947859255c1c48a1d020 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 1 Jun 2018 22:35:44 -0400 Subject: [PATCH 096/116] Bug 1466213 part 2. Remove nsIDOMGeoPositionError. r=qdot --- dom/geolocation/PositionError.cpp | 29 +++++-------------- dom/geolocation/PositionError.h | 12 ++++---- dom/geolocation/nsGeolocation.cpp | 14 ++++----- dom/interfaces/geolocation/moz.build | 1 - .../geolocation/nsIDOMGeoPositionError.idl | 24 --------------- .../nsIDOMGeoPositionErrorCallback.idl | 4 +-- dom/ipc/ContentParent.cpp | 10 ++----- dom/system/NetworkGeolocationProvider.js | 3 +- dom/system/linux/GpsdLocationProvider.cpp | 12 ++++---- .../mac/CoreLocationLocationProvider.mm | 4 +-- .../windows/WindowsLocationProvider.cpp | 6 ++-- .../geolocation/test_errorcheck.html | 7 +++-- .../test_geolocation_position_unavailable.js | 4 ++- 13 files changed, 45 insertions(+), 85 deletions(-) delete mode 100644 dom/interfaces/geolocation/nsIDOMGeoPositionError.idl diff --git a/dom/geolocation/PositionError.cpp b/dom/geolocation/PositionError.cpp index 38698fffeee3..1792d160571b 100644 --- a/dom/geolocation/PositionError.cpp +++ b/dom/geolocation/PositionError.cpp @@ -11,15 +11,10 @@ namespace mozilla { namespace dom { -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMGeoPositionError) - NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError) -NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent) -NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError) -NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError) +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PositionError, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PositionError, Release) PositionError::PositionError(Geolocation* aParent, int16_t aCode) : mCode(aCode) @@ -29,33 +24,23 @@ PositionError::PositionError(Geolocation* aParent, int16_t aCode) PositionError::~PositionError() = default; - -NS_IMETHODIMP -PositionError::GetCode(int16_t *aCode) -{ - NS_ENSURE_ARG_POINTER(aCode); - *aCode = Code(); - return NS_OK; -} - -NS_IMETHODIMP -PositionError::GetMessage(nsAString& aMessage) +void +PositionError::GetMessage(nsAString& aMessage) const { switch (mCode) { - case nsIDOMGeoPositionError::PERMISSION_DENIED: + case PositionErrorBinding::PERMISSION_DENIED: aMessage = NS_LITERAL_STRING("User denied geolocation prompt"); break; - case nsIDOMGeoPositionError::POSITION_UNAVAILABLE: + case PositionErrorBinding::POSITION_UNAVAILABLE: aMessage = NS_LITERAL_STRING("Unknown error acquiring position"); break; - case nsIDOMGeoPositionError::TIMEOUT: + case PositionErrorBinding::TIMEOUT: aMessage = NS_LITERAL_STRING("Position acquisition timed out"); break; default: break; } - return NS_OK; } nsWrapperCache* diff --git a/dom/geolocation/PositionError.h b/dom/geolocation/PositionError.h index 0ffa09b376fd..2f7de5bf376a 100644 --- a/dom/geolocation/PositionError.h +++ b/dom/geolocation/PositionError.h @@ -7,7 +7,6 @@ #ifndef mozilla_dom_PositionError_h #define mozilla_dom_PositionError_h -#include "nsIDOMGeoPositionError.h" #include "nsWrapperCache.h" #include "nsISupportsImpl.h" #include "nsCycleCollectionParticipant.h" @@ -21,14 +20,11 @@ class PositionErrorCallback; class Geolocation; typedef CallbackObjectHolder GeoPositionErrorCallback; -class PositionError final : public nsIDOMGeoPositionError, - public nsWrapperCache +class PositionError final : public nsWrapperCache { public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PositionError) - - NS_DECL_NSIDOMGEOPOSITIONERROR + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PositionError) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PositionError) PositionError(Geolocation* aParent, int16_t aCode); @@ -40,6 +36,8 @@ public: return mCode; } + void GetMessage(nsAString& aMessage) const; + void NotifyCallback(const GeoPositionErrorCallback& callback); private: ~PositionError(); diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp index 4154da993ad5..b27ac9392afe 100644 --- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/PositionError.h" +#include "mozilla/dom/PositionErrorBinding.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" @@ -22,7 +23,6 @@ #include "nsContentUtils.h" #include "nsGlobalWindow.h" #include "nsIDocument.h" -#include "nsIDOMGeoPositionError.h" #include "nsINamed.h" #include "nsIObserverService.h" #include "nsIScriptError.h" @@ -270,7 +270,7 @@ void nsGeolocationRequest::Notify() { SetTimeoutTimer(); - NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT); + NotifyErrorAndShutdown(PositionErrorBinding::TIMEOUT); } void @@ -346,7 +346,7 @@ nsGeolocationRequest::Cancel() return NS_OK; } - NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED); + NotifyError(PositionErrorBinding::PERMISSION_DENIED); return NS_OK; } @@ -414,7 +414,7 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) // if it is not a watch request and timeout is 0, // invoke the errorCallback (if present) with TIMEOUT code if (mOptions && mOptions->mTimeout == 0 && !mIsWatchPositionRequest) { - NotifyError(nsIDOMGeoPositionError::TIMEOUT); + NotifyError(PositionErrorBinding::TIMEOUT); return NS_OK; } @@ -425,7 +425,7 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) if (NS_FAILED(rv)) { // Location provider error - NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE); + NotifyError(PositionErrorBinding::POSITION_UNAVAILABLE); return NS_OK; } @@ -504,7 +504,7 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition) } if (!wrapped) { - NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE); + NotifyError(PositionErrorBinding::POSITION_UNAVAILABLE); return; } @@ -789,7 +789,7 @@ nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal) if (NS_FAILED(rv = mProvider->Startup()) || NS_FAILED(rv = mProvider->Watch(this))) { - NotifyError(nsIDOMGeoPositionError::POSITION_UNAVAILABLE); + NotifyError(PositionErrorBinding::POSITION_UNAVAILABLE); return rv; } diff --git a/dom/interfaces/geolocation/moz.build b/dom/interfaces/geolocation/moz.build index 827ccf858a4a..432eb74e113d 100644 --- a/dom/interfaces/geolocation/moz.build +++ b/dom/interfaces/geolocation/moz.build @@ -12,7 +12,6 @@ XPIDL_SOURCES += [ 'nsIDOMGeoPosition.idl', 'nsIDOMGeoPositionCallback.idl', 'nsIDOMGeoPositionCoords.idl', - 'nsIDOMGeoPositionError.idl', 'nsIDOMGeoPositionErrorCallback.idl', ] diff --git a/dom/interfaces/geolocation/nsIDOMGeoPositionError.idl b/dom/interfaces/geolocation/nsIDOMGeoPositionError.idl deleted file mode 100644 index a2405e28e796..000000000000 --- a/dom/interfaces/geolocation/nsIDOMGeoPositionError.idl +++ /dev/null @@ -1,24 +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/. */ - - -#include "domstubs.idl" - -// undef the GetMessage macro defined in winuser.h from the MS Platform SDK -%{C++ -#ifdef GetMessage -#undef GetMessage -#endif -%} - -[shim(PositionError), uuid(85255CC3-07BA-49FD-BC9B-18D2963DAF7F)] -interface nsIDOMGeoPositionError : nsISupports -{ - const unsigned short PERMISSION_DENIED = 1; - const unsigned short POSITION_UNAVAILABLE = 2; - const unsigned short TIMEOUT = 3; - - readonly attribute short code; - readonly attribute AString message; -}; diff --git a/dom/interfaces/geolocation/nsIDOMGeoPositionErrorCallback.idl b/dom/interfaces/geolocation/nsIDOMGeoPositionErrorCallback.idl index e2b707d8a9b2..62146d4394a7 100644 --- a/dom/interfaces/geolocation/nsIDOMGeoPositionErrorCallback.idl +++ b/dom/interfaces/geolocation/nsIDOMGeoPositionErrorCallback.idl @@ -5,9 +5,9 @@ #include "domstubs.idl" -interface nsIDOMGeoPositionError; +webidl PositionError; [scriptable, function, uuid(7D9B09D9-4843-43EB-A7A7-67F7DDA6B3C4)] interface nsIDOMGeoPositionErrorCallback : nsISupports { - void handleEvent(in nsIDOMGeoPositionError positionError); + void handleEvent(in PositionError positionError); }; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index c331e21a6660..d79f7be3fc1a 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -51,6 +51,7 @@ #include "mozilla/dom/PContentBridgeParent.h" #include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/dom/PCycleCollectWithLogsParent.h" +#include "mozilla/dom/PositionError.h" #include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/power/PowerManagerService.h" #include "mozilla/dom/Permissions.h" @@ -123,7 +124,6 @@ #include "nsIDocShellTreeOwner.h" #include "nsIDocument.h" #include "nsIDOMGeoGeolocation.h" -#include "nsIDOMGeoPositionError.h" #include "nsIDragService.h" #include "mozilla/dom/WakeLock.h" #include "nsIDOMWindow.h" @@ -3895,13 +3895,9 @@ ContentParent::HandleEvent(nsIDOMGeoPosition* postion) } NS_IMETHODIMP -ContentParent::HandleEvent(nsIDOMGeoPositionError* postionError) +ContentParent::HandleEvent(PositionError* positionError) { - int16_t errorCode; - nsresult rv; - rv = postionError->GetCode(&errorCode); - NS_ENSURE_SUCCESS(rv,rv); - Unused << SendGeolocationError(errorCode); + Unused << SendGeolocationError(positionError->Code()); return NS_OK; } diff --git a/dom/system/NetworkGeolocationProvider.js b/dom/system/NetworkGeolocationProvider.js index bfa5a2aad851..40119de5025f 100644 --- a/dom/system/NetworkGeolocationProvider.js +++ b/dom/system/NetworkGeolocationProvider.js @@ -9,7 +9,8 @@ ChromeUtils.import("resource://gre/modules/Services.jsm"); Cu.importGlobalProperties(["XMLHttpRequest"]); -const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE; +// PositionError has no interface object, so we can't use that here. +const POSITION_UNAVAILABLE = 2; var gLoggingEnabled = false; diff --git a/dom/system/linux/GpsdLocationProvider.cpp b/dom/system/linux/GpsdLocationProvider.cpp index eeee806dc174..759d8f8c932c 100644 --- a/dom/system/linux/GpsdLocationProvider.cpp +++ b/dom/system/linux/GpsdLocationProvider.cpp @@ -11,8 +11,8 @@ #include "mozilla/Atomics.h" #include "mozilla/FloatingPoint.h" #include "mozilla/LazyIdleThread.h" +#include "mozilla/dom/PositionErrorBinding.h" #include "nsGeoPosition.h" -#include "nsIDOMGeoPositionError.h" #include "nsProxyRelease.h" #include "nsThreadUtils.h" @@ -185,7 +185,7 @@ public: err = PollLoop5(); break; default: - err = nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + err = PositionErrorBinding::POSITION_UNAVAILABLE; break; } @@ -301,7 +301,7 @@ protected: return err; #else - return nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + return PositionErrorBinding::POSITION_UNAVAILABLE; #endif // GPSD_MAJOR_API_VERSION } @@ -313,13 +313,13 @@ protected: case EPERM: MOZ_FALLTHROUGH; case EROFS: - return nsIDOMGeoPositionError::PERMISSION_DENIED; + return PositionErrorBinding::PERMISSION_DENIED; case ETIME: MOZ_FALLTHROUGH; case ETIMEDOUT: - return nsIDOMGeoPositionError::TIMEOUT; + return PositionErrorBinding::TIMEOUT; default: - return nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + return PositionErrorBinding::POSITION_UNAVAILABLE; } } diff --git a/dom/system/mac/CoreLocationLocationProvider.mm b/dom/system/mac/CoreLocationLocationProvider.mm index 5cb3d4f93eec..0a4e26047a0f 100644 --- a/dom/system/mac/CoreLocationLocationProvider.mm +++ b/dom/system/mac/CoreLocationLocationProvider.mm @@ -9,11 +9,11 @@ #include "nsGeoPosition.h" #include "nsIConsoleService.h" #include "nsServiceManagerUtils.h" -#include "nsIDOMGeoPositionError.h" #include "CoreLocationLocationProvider.h" #include "nsCocoaFeatures.h" #include "prtime.h" #include "mozilla/Telemetry.h" +#include "mozilla/dom/PositionErrorBinding.h" #include "MLSFallback.h" #include @@ -67,7 +67,7 @@ static const CLLocationAccuracy kDEFAULT_ACCURACY = kCLLocationAccuracyNearestTe console->LogStringMessage(NS_ConvertUTF8toUTF16([message UTF8String]).get()); if ([aError code] == kCLErrorDenied) { - mProvider->NotifyError(nsIDOMGeoPositionError::PERMISSION_DENIED); + mProvider->NotifyError(dom::PositionErrorBinding::PERMISSION_DENIED); return; } diff --git a/dom/system/windows/WindowsLocationProvider.cpp b/dom/system/windows/WindowsLocationProvider.cpp index fa7f8d8be1d8..e9ccdc7a3548 100644 --- a/dom/system/windows/WindowsLocationProvider.cpp +++ b/dom/system/windows/WindowsLocationProvider.cpp @@ -6,11 +6,11 @@ #include "WindowsLocationProvider.h" #include "nsGeoPosition.h" -#include "nsIDOMGeoPositionError.h" #include "nsComponentManagerUtils.h" #include "prtime.h" #include "MLSFallback.h" #include "mozilla/Telemetry.h" +#include "mozilla/dom/PositionErrorBinding.h" namespace mozilla { namespace dom { @@ -129,11 +129,11 @@ LocationEvent::OnStatusChanged(REFIID aReportType, uint16_t err; switch (aStatus) { case REPORT_ACCESS_DENIED: - err = nsIDOMGeoPositionError::PERMISSION_DENIED; + err = PositionErrorBinding::PERMISSION_DENIED; break; case REPORT_NOT_SUPPORTED: case REPORT_ERROR: - err = nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + err = PositionErrorBinding::POSITION_UNAVAILABLE; break; default: return S_OK; diff --git a/dom/tests/mochitest/geolocation/test_errorcheck.html b/dom/tests/mochitest/geolocation/test_errorcheck.html index ffe5ce882b7b..cdab79c490d9 100644 --- a/dom/tests/mochitest/geolocation/test_errorcheck.html +++ b/dom/tests/mochitest/geolocation/test_errorcheck.html @@ -30,8 +30,11 @@ function test1() { } function errorCallback(error) { - is(error.code, - SpecialPowers.Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE, "Geolocation error handler fired"); + // PositionError has no interface object, so we can't get constants off that. + is(error.code, error.POSITION_UNAVAILABLE, + "Geolocation error handler fired"); + is(error.POSITION_UNAVAILABLE, 2, + "Value of POSITION_UNAVAILABLE should be correct"); SimpleTest.finish(); } diff --git a/dom/tests/unit/test_geolocation_position_unavailable.js b/dom/tests/unit/test_geolocation_position_unavailable.js index 74440f86206f..de0a5fd5e026 100644 --- a/dom/tests/unit/test_geolocation_position_unavailable.js +++ b/dom/tests/unit/test_geolocation_position_unavailable.js @@ -4,7 +4,9 @@ function successCallback() { } function errorCallback(err) { - Assert.equal(Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE, err.code); + // PositionError has no interface object, so we can't get constants off that. + Assert.equal(err.POSITION_UNAVAILABLE, err.code); + Assert.equal(2, err.code); do_test_finished(); } From 32774b2c1db0e51539f1f173979517ebadaa3cd5 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 2 Jun 2018 00:53:22 -0400 Subject: [PATCH 097/116] Bug 1465875 followup. Fix some Android code that ends up with null elements and was getting false from instanceof as a result. r=bzbarsky --- .../chrome/geckoview/GeckoViewSelectionActionContent.js | 2 +- mobile/android/modules/ActionBarHandler.jsm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/geckoview/GeckoViewSelectionActionContent.js b/mobile/android/chrome/geckoview/GeckoViewSelectionActionContent.js index 5b09f035e32b..4f685248223b 100644 --- a/mobile/android/chrome/geckoview/GeckoViewSelectionActionContent.js +++ b/mobile/android/chrome/geckoview/GeckoViewSelectionActionContent.js @@ -77,7 +77,7 @@ class GeckoViewSelectionActionContent extends GeckoViewContentModule { _getSelectionController(aEvent) { if (aEvent.selectionEditable) { const focus = aEvent.target.activeElement; - if (focus.editor) { + if (focus && focus.editor) { return focus.editor.selectionController; } } diff --git a/mobile/android/modules/ActionBarHandler.jsm b/mobile/android/modules/ActionBarHandler.jsm index 471d056d3c95..83f2335f82d3 100644 --- a/mobile/android/modules/ActionBarHandler.jsm +++ b/mobile/android/modules/ActionBarHandler.jsm @@ -760,6 +760,9 @@ var ActionBarHandler = { * Tests whether a given element is editable. */ _isElementEditable: function(element) { + if (!element) { + return false; + } let elementClass = ChromeUtils.getClassName(element); return elementClass === "HTMLInputElement" || elementClass === "HTMLTextAreaElement"; From 97193c41783b64edfbb3eb71cc27a4ab9121e419 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 2 Jun 2018 01:26:00 -0400 Subject: [PATCH 098/116] Bug 1464784. Hold a strong ref to the document in callers of ConvertNodesOrStringsIntoNode. r=smaug --- dom/base/nsINode.cpp | 22 +++++++++++----------- dom/base/nsINode.h | 16 ++++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 423418a6619c..84d8f898629d 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -1446,7 +1446,7 @@ GetNodeFromNodeOrString(const OwningNodeOrString& aNode, * https://dom.spec.whatwg.org/#converting-nodes-into-a-node for |prepend()|, * |append()|, |before()|, |after()|, and |replaceWith()| APIs. */ -static already_AddRefed +MOZ_CAN_RUN_SCRIPT static already_AddRefed ConvertNodesOrStringsIntoNode(const Sequence& aNodes, nsIDocument* aDocument, ErrorResult& aRv) @@ -1529,8 +1529,8 @@ nsINode::Before(const Sequence& aNodes, nsCOMPtr viablePreviousSibling = FindViablePreviousSibling(*this, aNodes); - nsCOMPtr node = - ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv); + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); if (aRv.Failed()) { return; } @@ -1552,8 +1552,8 @@ nsINode::After(const Sequence& aNodes, nsCOMPtr viableNextSibling = FindViableNextSibling(*this, aNodes); - nsCOMPtr node = - ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv); + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); if (aRv.Failed()) { return; } @@ -1572,8 +1572,8 @@ nsINode::ReplaceWith(const Sequence& aNodes, nsCOMPtr viableNextSibling = FindViableNextSibling(*this, aNodes); - nsCOMPtr node = - ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv); + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); if (aRv.Failed()) { return; } @@ -1628,8 +1628,8 @@ void nsINode::Prepend(const Sequence& aNodes, ErrorResult& aRv) { - nsCOMPtr node = - ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv); + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); if (aRv.Failed()) { return; } @@ -1642,8 +1642,8 @@ void nsINode::Append(const Sequence& aNodes, ErrorResult& aRv) { - nsCOMPtr node = - ConvertNodesOrStringsIntoNode(aNodes, OwnerDoc(), aRv); + nsCOMPtr doc = OwnerDoc(); + nsCOMPtr node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv); if (aRv.Failed()) { return; } diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 8f4535501121..890d1674def9 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1859,10 +1859,12 @@ public: mozilla::dom::Element* GetPreviousElementSibling() const; mozilla::dom::Element* GetNextElementSibling() const; - void Before(const Sequence& aNodes, ErrorResult& aRv); - void After(const Sequence& aNodes, ErrorResult& aRv); - void ReplaceWith(const Sequence& aNodes, - ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void Before(const Sequence& aNodes, + ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void After(const Sequence& aNodes, + ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void ReplaceWith(const Sequence& aNodes, + ErrorResult& aRv); /** * Remove this node from its parent, if any. */ @@ -1872,8 +1874,10 @@ public: mozilla::dom::Element* GetFirstElementChild() const; mozilla::dom::Element* GetLastElementChild() const; - void Prepend(const Sequence& aNodes, ErrorResult& aRv); - void Append(const Sequence& aNodes, ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void Prepend(const Sequence& aNodes, + ErrorResult& aRv); + MOZ_CAN_RUN_SCRIPT void Append(const Sequence& aNodes, + ErrorResult& aRv); void GetBoxQuads(const BoxQuadOptions& aOptions, nsTArray >& aResult, From 1e9c395548492c9b19a2a2712213fd4e89a768bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 1 Jun 2018 18:30:30 +0200 Subject: [PATCH 099/116] Bug 1466168: Remove mozilla::Forward in favor of std::forward. r=froydnj Same approach as the other bug, mostly replacing automatically by removing 'using mozilla::Forward;' and then: s/mozilla::Forward/std::forward/ s/Forward(aRange)) {} + mRange(std::forward(aRange)) {} xpcAccessibleTextRange() {} ~xpcAccessibleTextRange() {} diff --git a/devtools/shared/heapsnapshot/HeapSnapshot.cpp b/devtools/shared/heapsnapshot/HeapSnapshot.cpp index 187bba44a9a5..4ba20a69d40d 100644 --- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp +++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp @@ -918,13 +918,13 @@ class TwoByteString : public Variant - MOZ_IMPLICIT TwoByteString(T&& rhs) : Base(Forward(rhs)) { } + MOZ_IMPLICIT TwoByteString(T&& rhs) : Base(std::forward(rhs)) { } template TwoByteString& operator=(T&& rhs) { MOZ_ASSERT(this != &rhs, "self-move disallowed"); this->~TwoByteString(); - new (this) TwoByteString(Forward(rhs)); + new (this) TwoByteString(std::forward(rhs)); return *this; } diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index 4cbc7833aeb7..99773bee3bd1 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -13,7 +13,7 @@ #include "mozilla/AutoRestore.h" #include "mozilla/AsyncEventDispatcher.h" // For AsyncEventDispatcher #include "mozilla/Maybe.h" // For Maybe -#include "mozilla/TypeTraits.h" // For Forward<> +#include "mozilla/TypeTraits.h" // For std::forward<> #include "nsAnimationManager.h" // For CSSAnimation #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch #include "nsIDocument.h" // For nsIDocument diff --git a/dom/animation/EffectCompositor.cpp b/dom/animation/EffectCompositor.cpp index 0ac96e4e4416..2b71fb945c07 100644 --- a/dom/animation/EffectCompositor.cpp +++ b/dom/animation/EffectCompositor.cpp @@ -24,7 +24,7 @@ #include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation #include "mozilla/ServoStyleSet.h" #include "mozilla/StyleAnimationValue.h" -#include "mozilla/TypeTraits.h" // For Forward<> +#include "mozilla/TypeTraits.h" // For std::forward<> #include "nsContentUtils.h" #include "nsCSSPseudoElements.h" #include "nsCSSPropertyIDSet.h" diff --git a/dom/bindings/BindingDeclarations.h b/dom/bindings/BindingDeclarations.h index a5390f52fa91..731190bf83a4 100644 --- a/dom/bindings/BindingDeclarations.h +++ b/dom/bindings/BindingDeclarations.h @@ -178,7 +178,7 @@ public: template InternalType& Construct(Args&&... aArgs) { - mImpl.emplace(Forward(aArgs)...); + mImpl.emplace(std::forward(aArgs)...); return *mImpl; } diff --git a/dom/bindings/ErrorResult.h b/dom/bindings/ErrorResult.h index 9211c032bd13..71f163fcf62e 100644 --- a/dom/bindings/ErrorResult.h +++ b/dom/bindings/ErrorResult.h @@ -78,7 +78,7 @@ inline bool ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, Ts&&... aArgs) { binding_detail::ThrowErrorMessage(aCx, static_cast(aErrorNumber), - mozilla::Forward(aArgs)...); + std::forward(aArgs)...); return false; } @@ -97,7 +97,7 @@ struct StringArrayAppender return; } aArgs.AppendElement(aFirst); - Append(aArgs, aCount - 1, Forward(aOtherArgs)...); + Append(aArgs, aCount - 1, std::forward(aOtherArgs)...); } }; @@ -293,14 +293,14 @@ public: void ThrowTypeError(Ts&&... messageArgs) { ThrowErrorWithMessage(NS_ERROR_INTERNAL_ERRORRESULT_TYPEERROR, - Forward(messageArgs)...); + std::forward(messageArgs)...); } template void ThrowRangeError(Ts&&... messageArgs) { ThrowErrorWithMessage(NS_ERROR_INTERNAL_ERRORRESULT_RANGEERROR, - Forward(messageArgs)...); + std::forward(messageArgs)...); } bool IsErrorWithMessage() const @@ -434,7 +434,7 @@ private: nsTArray& messageArgsArray = CreateErrorMessageHelper(errorNumber, errorType); uint16_t argCount = dom::GetErrorArgCount(errorNumber); dom::StringArrayAppender::Append(messageArgsArray, argCount, - Forward(messageArgs)...); + std::forward(messageArgs)...); #ifdef DEBUG mUnionState = HasMessage; #endif // DEBUG diff --git a/dom/clients/manager/ClientManagerOpParent.cpp b/dom/clients/manager/ClientManagerOpParent.cpp index 108effafe779..8edd68782e5c 100644 --- a/dom/clients/manager/ClientManagerOpParent.cpp +++ b/dom/clients/manager/ClientManagerOpParent.cpp @@ -20,7 +20,7 @@ ClientManagerOpParent::DoServiceOp(Method aMethod, Args&&... aArgs) { // Note, we need perfect forarding of the template type in order // to allow already_AddRefed<> to be passed as an arg. - RefPtr p = (mService->*aMethod)(Forward(aArgs)...); + RefPtr p = (mService->*aMethod)(std::forward(aArgs)...); // Capturing `this` is safe here because we disconnect the promise in // ActorDestroy() which ensures neither lambda is called if the actor diff --git a/dom/console/nsIConsoleReportCollector.h b/dom/console/nsIConsoleReportCollector.h index 5ed10d9ad1b9..20b95eca8b00 100644 --- a/dom/console/nsIConsoleReportCollector.h +++ b/dom/console/nsIConsoleReportCollector.h @@ -61,7 +61,7 @@ public: { nsTArray params; mozilla::dom::StringArrayAppender::Append(params, sizeof...(Params), - mozilla::Forward(aParams)...); + std::forward(aParams)...); AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile, aSourceFileURI, aLineNumber, aColumnNumber, aMessageName, params); } diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index e8343fb8f7d0..d06348c2fbbb 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4855,7 +4855,7 @@ HTMLMediaElement::SetupDecoder(DecoderType* aDecoder, LoadArgs&&... aArgs) aDecoder, aDecoder->ContainerType().OriginalString().Data())); - nsresult rv = aDecoder->Load(Forward(aArgs)...); + nsresult rv = aDecoder->Load(std::forward(aArgs)...); if (NS_FAILED(rv)) { aDecoder->Shutdown(); LOG(LogLevel::Debug, ("%p Failed to load for decoder %p", this, aDecoder)); diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 94481f4b96a7..0d7e7034e4ba 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -331,7 +331,7 @@ template int AudioStream::InvokeCubeb(Function aFunction, Args&&... aArgs) { MonitorAutoUnlock mon(mMonitor); - return aFunction(mCubebStream.get(), Forward(aArgs)...); + return aFunction(mCubebStream.get(), std::forward(aArgs)...); } nsresult diff --git a/dom/media/Intervals.h b/dom/media/Intervals.h index a45c5a4eb719..af633d4782e6 100644 --- a/dom/media/Intervals.h +++ b/dom/media/Intervals.h @@ -49,8 +49,8 @@ public: template Interval(StartArg&& aStart, EndArg&& aEnd) - : mStart(Forward(aStart)) - , mEnd(Forward(aEnd)) + : mStart(std::forward(aStart)) + , mEnd(std::forward(aEnd)) , mFuzz() { MOZ_ASSERT(aStart <= aEnd); @@ -58,9 +58,9 @@ public: template Interval(StartArg&& aStart, EndArg&& aEnd, FuzzArg&& aFuzz) - : mStart(Forward(aStart)) - , mEnd(Forward(aEnd)) - , mFuzz(Forward(aFuzz)) + : mStart(std::forward(aStart)) + , mEnd(std::forward(aEnd)) + , mFuzz(std::forward(aFuzz)) { MOZ_ASSERT(aStart <= aEnd); } diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 9de68db9ef2d..8d64e03dc168 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -275,7 +275,7 @@ protected: // So we 1) pass the parameters by reference, but then 2) immediately copy // them into a Tuple to be safe against modification, and finally 3) move // the elements of the Tuple into the final function call. - auto copiedArgs = MakeTuple(Forward(aArgs)...); + auto copiedArgs = MakeTuple(std::forward(aArgs)...); // Copy mMaster which will reset to null. auto master = mMaster; diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 17107ff2d64d..1840f0399055 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -145,7 +145,7 @@ struct MediaPlaybackEvent template MediaPlaybackEvent(EventType aType, T&& aArg) : mType(aType) - , mData(Forward(aArg)) + , mData(std::forward(aArg)) { } }; diff --git a/dom/media/MediaEventSource.h b/dom/media/MediaEventSource.h index fda2fa6cdb8d..4ac91a187295 100644 --- a/dom/media/MediaEventSource.h +++ b/dom/media/MediaEventSource.h @@ -138,7 +138,7 @@ public: "detail::Listener::ApplyWithArgs", this, &Listener::ApplyWithArgs, - Forward(aEvents)...)); + std::forward(aEvents)...)); } else { DispatchTask(NewRunnableMethod( "detail::Listener::ApplyWithNoArgs", this, &Listener::ApplyWithNoArgs)); @@ -178,7 +178,7 @@ public: template ListenerImpl(Target* aTarget, F&& aFunction) : mTarget(aTarget) - , mFunction(Forward(aFunction)) + , mFunction(std::forward(aFunction)) { } @@ -345,7 +345,7 @@ class MediaEventSourceImpl { MOZ_ASSERT(Lp == ListenerPolicy::NonExclusive || mListeners.IsEmpty()); auto l = mListeners.AppendElement(); *l = new ListenerImpl( - aTarget, Forward(aFunction)); + aTarget, std::forward(aFunction)); return MediaEventListener(*l); } @@ -383,13 +383,13 @@ public: template MediaEventListener Connect(AbstractThread* aTarget, Function&& aFunction) { - return ConnectInternal(aTarget, Forward(aFunction)); + return ConnectInternal(aTarget, std::forward(aFunction)); } template MediaEventListener Connect(nsIEventTarget* aTarget, Function&& aFunction) { - return ConnectInternal(aTarget, Forward(aFunction)); + return ConnectInternal(aTarget, std::forward(aFunction)); } /** @@ -430,7 +430,7 @@ protected: mListeners.RemoveElementAt(i); continue; } - l->Dispatch(Forward(aEvents)...); + l->Dispatch(std::forward(aEvents)...); } } @@ -482,7 +482,7 @@ class MediaEventProducerExc : public MediaEventSourceExc { public: template void Notify(Ts&&... aEvents) { - this->NotifyInternal(Forward(aEvents)...); + this->NotifyInternal(std::forward(aEvents)...); } }; diff --git a/dom/media/MediaInfo.h b/dom/media/MediaInfo.h index 9f47014e380d..9223b57f61c9 100644 --- a/dom/media/MediaInfo.h +++ b/dom/media/MediaInfo.h @@ -436,7 +436,7 @@ public: template InitData(const nsAString& aType, AInitDatas&& aInitData) : mType(aType) - , mInitData(Forward(aInitData)) + , mInitData(std::forward(aInitData)) { } @@ -463,7 +463,7 @@ public: template void AddInitData(const nsAString& aType, AInitDatas&& aInitData) { - mInitDatas.AppendElement(InitData(aType, Forward(aInitData))); + mInitDatas.AppendElement(InitData(aType, std::forward(aInitData))); mEncrypted = true; } diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index e7543dbb58e3..57874c079950 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -2243,7 +2243,7 @@ MediaManager::PostTask(const char* aName, FunctionType&& aFunction) MozPromiseHolder holder; RefPtr promise = holder.Ensure(aName); MediaManager::PostTask(NS_NewRunnableFunction(aName, - [h = std::move(holder), func = Forward(aFunction)]() mutable + [h = std::move(holder), func = std::forward(aFunction)]() mutable { func(h); })); diff --git a/dom/media/MediaSegment.h b/dom/media/MediaSegment.h index 04211d6eb790..df68f7fe769c 100644 --- a/dom/media/MediaSegment.h +++ b/dom/media/MediaSegment.h @@ -155,7 +155,7 @@ public: */ void SetLastPrincipalHandle(PrincipalHandle aLastPrincipalHandle) { - mLastPrincipalHandle = Forward(aLastPrincipalHandle); + mLastPrincipalHandle = std::forward(aLastPrincipalHandle); } /** diff --git a/dom/media/MediaTimer.h b/dom/media/MediaTimer.h index 6568b5d55f1a..ad9c0620eb93 100644 --- a/dom/media/MediaTimer.h +++ b/dom/media/MediaTimer.h @@ -153,8 +153,8 @@ public: mTarget = aTarget; mMediaTimer->WaitUntil(mTarget, __func__)->Then( mTargetThread, __func__, - Forward(aResolver), - Forward(aRejector)) + std::forward(aResolver), + std::forward(aRejector)) ->Track(mRequest); } diff --git a/dom/media/VideoSegment.h b/dom/media/VideoSegment.h index 83c7864c2d9c..f26eddee6d0a 100644 --- a/dom/media/VideoSegment.h +++ b/dom/media/VideoSegment.h @@ -42,7 +42,7 @@ public: bool GetForceBlack() const { return mForceBlack; } void SetPrincipalHandle(PrincipalHandle aPrincipalHandle) { - mPrincipalHandle = Forward(aPrincipalHandle); + mPrincipalHandle = std::forward(aPrincipalHandle); } const PrincipalHandle& GetPrincipalHandle() const { return mPrincipalHandle; } const gfx::IntSize& GetIntrinsicSize() const { return mIntrinsicSize; } diff --git a/dom/media/doctor/DecoderDoctorLogger.h b/dom/media/doctor/DecoderDoctorLogger.h index be5c137cb541..7a4b0797c649 100644 --- a/dom/media/doctor/DecoderDoctorLogger.h +++ b/dom/media/doctor/DecoderDoctorLogger.h @@ -87,7 +87,7 @@ public: aSubjectPointer, aCategory, aLabel, - DDLogValue{ Forward(aValue) }); + DDLogValue{ std::forward(aValue) }); } template @@ -100,7 +100,7 @@ public: aSubject, aCategory, aLabel, - Forward(aValue)); + std::forward(aValue)); } // EagerLogValue that can explicitly take strings, as the templated function @@ -154,7 +154,7 @@ public: aCategory, aLabel, DDLogValue{ - nsCString{ nsPrintfCString(aFormat, Forward(aArgs)...) } }); + nsCString{ nsPrintfCString(aFormat, std::forward(aArgs)...) } }); } template @@ -182,7 +182,7 @@ public: aCategory, aLabel, aFormat, - Forward(aArgs)...); + std::forward(aArgs)...); } static void MozLogPrintf(const char* aSubjectTypeName, @@ -209,7 +209,7 @@ public: const char* aFormat, Args&&... aArgs) { - nsCString printed = nsPrintfCString(aFormat, Forward(aArgs)...); + nsCString printed = nsPrintfCString(aFormat, std::forward(aArgs)...); Log(aSubjectTypeName, aSubjectPointer, CategoryForMozLogLevel(aLogLevel), @@ -245,7 +245,7 @@ public: aLogModule, aLogLevel, aFormat, - Forward(aArgs)...); + std::forward(aArgs)...); } // Special logging functions. Consider using DecoderDoctorLifeLogger to diff --git a/dom/media/gmp/ChromiumCDMCallbackProxy.cpp b/dom/media/gmp/ChromiumCDMCallbackProxy.cpp index d5f7f893902f..369baca69f67 100644 --- a/dom/media/gmp/ChromiumCDMCallbackProxy.cpp +++ b/dom/media/gmp/ChromiumCDMCallbackProxy.cpp @@ -21,7 +21,7 @@ void ChromiumCDMCallbackProxy::DispatchToMainThread(const char* const aLabel, aLabel, mProxy, aFunc, - Forward(aArgs)...), + std::forward(aArgs)...), NS_DISPATCH_NORMAL); } diff --git a/dom/media/gmp/ChromiumCDMChild.cpp b/dom/media/gmp/ChromiumCDMChild.cpp index a42b9b69e4f2..1eea014af7f0 100644 --- a/dom/media/gmp/ChromiumCDMChild.cpp +++ b/dom/media/gmp/ChromiumCDMChild.cpp @@ -197,7 +197,7 @@ ChromiumCDMChild::CallMethod(MethodType aMethod, ParamType&&... aParams) MOZ_ASSERT(IsOnMessageLoopThread()); // Avoid calling member function after destroy. if (!mDestroyed) { - Unused << (this->*aMethod)(Forward(aParams)...); + Unused << (this->*aMethod)(std::forward(aParams)...); } } @@ -208,7 +208,7 @@ ChromiumCDMChild::CallOnMessageLoopThread(const char* const aName, ParamType&&... aParams) { if (IsOnMessageLoopThread()) { - CallMethod(aMethod, Forward(aParams)...); + CallMethod(aMethod, std::forward(aParams)...); } else { auto m = &ChromiumCDMChild::CallMethod< decltype(aMethod), const typename RemoveReference::Type&...>; @@ -219,7 +219,7 @@ ChromiumCDMChild::CallOnMessageLoopThread(const char* const aName, this, m, aMethod, - Forward(aParams)...); + std::forward(aParams)...); mPlugin->GMPMessageLoop()->PostTask(t.forget()); } } diff --git a/dom/media/mp4/MP4Metadata.h b/dom/media/mp4/MP4Metadata.h index 5f318700fb74..ef91e108586e 100644 --- a/dom/media/mp4/MP4Metadata.h +++ b/dom/media/mp4/MP4Metadata.h @@ -67,7 +67,7 @@ public: public: template ResultAndType(M2&& aM, T2&& aT) - : mResult(Forward(aM)), mT(Forward(aT)) + : mResult(std::forward(aM)), mT(std::forward(aT)) { } ResultAndType(const ResultAndType&) = default; diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 92f3bf3ccc20..16409f6dc2c3 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -113,7 +113,7 @@ public: void AddToCheckList(Func&& aChecker) { - mCheckerList.AppendElement(mozilla::Forward(aChecker)); + mCheckerList.AppendElement(std::forward(aChecker)); } void diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index f21d20005ff4..8878fca23532 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -71,7 +71,7 @@ struct MOZ_STACK_CLASS CreateDecoderParams final CreateDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args) : mConfig(aConfig) { - Set(mozilla::Forward(a1), mozilla::Forward(args)...); + Set(std::forward(a1), std::forward(args)...); } const VideoInfo& VideoConfig() const @@ -140,8 +140,8 @@ private: template void Set(T1&& a1, T2&& a2, Ts&&... args) { - Set(mozilla::Forward(a1)); - Set(mozilla::Forward(a2), mozilla::Forward(args)...); + Set(std::forward(a1)); + Set(std::forward(a2), std::forward(args)...); } }; diff --git a/dom/media/systemservices/CamerasChild.h b/dom/media/systemservices/CamerasChild.h index 0b757345118e..11cd6c8d8a89 100644 --- a/dom/media/systemservices/CamerasChild.h +++ b/dom/media/systemservices/CamerasChild.h @@ -142,7 +142,7 @@ int GetChildAndCall(MEM_FUN&& f, ARGS&&... args) OffTheBooksMutexAutoLock lock(CamerasSingleton::Mutex()); CamerasChild* child = GetCamerasChild(); if (child) { - return (child->*f)(mozilla::Forward(args)...); + return (child->*f)(std::forward(args)...); } else { return -1; } diff --git a/dom/media/systemservices/MediaTaskUtils.h b/dom/media/systemservices/MediaTaskUtils.h index ef782890b87f..8c09e47f7266 100644 --- a/dom/media/systemservices/MediaTaskUtils.h +++ b/dom/media/systemservices/MediaTaskUtils.h @@ -45,7 +45,7 @@ already_AddRefed> NewTaskFrom(OnRunType&& aOnRun) { typedef LambdaTask LambdaType; - RefPtr lambda = new LambdaType(Forward(aOnRun)); + RefPtr lambda = new LambdaType(std::forward(aOnRun)); return lambda.forget(); } diff --git a/dom/media/systemservices/MediaUtils.h b/dom/media/systemservices/MediaUtils.h index 77093d35bde1..39482e64e665 100644 --- a/dom/media/systemservices/MediaUtils.h +++ b/dom/media/systemservices/MediaUtils.h @@ -81,7 +81,7 @@ public: template void Then(OnSuccessType&& aOnSuccess) { - Then(Forward(aOnSuccess), [](ErrorType&){}); + Then(std::forward(aOnSuccess), [](ErrorType&){}); } template @@ -105,8 +105,8 @@ public: OnSuccessType mOnSuccess; OnFailureType mOnFailure; }; - mFunctors = MakeUnique(Forward(aOnSuccess), - Forward(aOnFailure)); + mFunctors = MakeUnique(std::forward(aOnSuccess), + std::forward(aOnFailure)); if (mDone) { if (!mRejected) { mFunctors->Succeed(mValue); @@ -216,7 +216,7 @@ already_AddRefed> NewRunnableFrom(OnRunType&& aOnRun) { typedef LambdaRunnable LambdaType; - RefPtr lambda = new LambdaType(Forward(aOnRun)); + RefPtr lambda = new LambdaType(std::forward(aOnRun)); return lambda.forget(); } @@ -448,13 +448,13 @@ Await( __func__, [&](ResolveValueType&& aResolveValue) { MonitorAutoLock lock(mon); - aResolveFunction(Forward(aResolveValue)); + aResolveFunction(std::forward(aResolveValue)); done = true; mon.Notify(); }, [&](RejectValueType&& aRejectValue) { MonitorAutoLock lock(mon); - aRejectFunction(Forward(aRejectValue)); + aRejectFunction(std::forward(aRejectValue)); done = true; mon.Notify(); }); diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.h b/dom/media/webrtc/MediaEngineRemoteVideoSource.h index 24fac8befc62..a9fdce62bf8d 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h @@ -71,7 +71,7 @@ class MediaEngineRemoteVideoSource : public MediaEngineSource, struct CapabilityCandidate { explicit CapabilityCandidate(webrtc::CaptureCapability&& aCapability, uint32_t aDistance = 0) - : mCapability(Forward(aCapability)) + : mCapability(std::forward(aCapability)) , mDistance(aDistance) {} const webrtc::CaptureCapability mCapability; diff --git a/dom/serviceworkers/ServiceWorkerEvents.cpp b/dom/serviceworkers/ServiceWorkerEvents.cpp index f0f4259ae015..fe39cf77cd17 100644 --- a/dom/serviceworkers/ServiceWorkerEvents.cpp +++ b/dom/serviceworkers/ServiceWorkerEvents.cpp @@ -87,7 +87,7 @@ AsyncLog(nsIInterceptedChannel* aInterceptedChannel, { nsTArray paramsList(sizeof...(Params) + 1); StringArrayAppender::Append(paramsList, sizeof...(Params) + 1, - aFirstParam, Forward(aParams)...); + aFirstParam, std::forward(aParams)...); AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber, aRespondWithColumnNumber, aMessageName, paramsList); } @@ -559,7 +559,7 @@ public: mMessageName = aMessageName; mParams.Clear(); StringArrayAppender::Append(mParams, sizeof...(Params), - Forward(aParams)...); + std::forward(aParams)...); } template @@ -579,7 +579,7 @@ public: mMessageName = aMessageName; mParams.Clear(); StringArrayAppender::Append(mParams, sizeof...(Params), - Forward(aParams)...); + std::forward(aParams)...); } void Reset() diff --git a/gfx/2d/DrawingJob.h b/gfx/2d/DrawingJob.h index 0c8f470b5cf8..61371b797aa2 100644 --- a/gfx/2d/DrawingJob.h +++ b/gfx/2d/DrawingJob.h @@ -74,7 +74,7 @@ public: { static_assert(IsBaseOf::value, "T must derive from DrawingCommand"); - return mCommands->mStorage.Alloc(Forward(aArgs)...); + return mCommands->mStorage.Alloc(std::forward(aArgs)...); } bool HasCommands() const { return !!mCommands; } diff --git a/gfx/2d/IterableArena.h b/gfx/2d/IterableArena.h index ea0f8f91e6bf..d37148687aa4 100644 --- a/gfx/2d/IterableArena.h +++ b/gfx/2d/IterableArena.h @@ -78,7 +78,7 @@ public: if (offset < 0) { return offset; } - new (storage) T(Forward(aArgs)...); + new (storage) T(std::forward(aArgs)...); return offset; } diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp index feaa19189f95..2383c3901cf9 100644 --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -310,7 +310,7 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType, // Initialize the decoder, copying settings from @aICODecoder. decoder->SetMetadataDecode(aIsMetadataDecode); - decoder->SetIterator(Forward(aIterator)); + decoder->SetIterator(std::forward(aIterator)); if (!aIsMetadataDecode) { decoder->SetOutputSize(aICODecoder->OutputSize()); } diff --git a/image/SurfacePipe.h b/image/SurfacePipe.h index 9d0baa211d7e..854afb7f6716 100644 --- a/image/SurfacePipe.h +++ b/image/SurfacePipe.h @@ -172,7 +172,7 @@ public: WriteState WritePixels(Func aFunc) { Maybe result; - while (!(result = DoWritePixelsToRow(Forward(aFunc)))) { } + while (!(result = DoWritePixelsToRow(std::forward(aFunc)))) { } return *result; } @@ -209,7 +209,7 @@ public: WriteState WritePixelBlocks(Func aFunc) { Maybe result; - while (!(result = DoWritePixelBlockToRow(Forward(aFunc)))) { } + while (!(result = DoWritePixelBlockToRow(std::forward(aFunc)))) { } return *result; } @@ -246,7 +246,7 @@ public: template WriteState WritePixelsToRow(Func aFunc) { - return DoWritePixelsToRow(Forward(aFunc)) + return DoWritePixelsToRow(std::forward(aFunc)) .valueOr(WriteState::NEED_MORE_DATA); } @@ -639,7 +639,7 @@ public: WriteState WritePixels(Func aFunc) { MOZ_ASSERT(mHead, "Use before configured!"); - return mHead->WritePixels(Forward(aFunc)); + return mHead->WritePixels(std::forward(aFunc)); } /** @@ -653,7 +653,7 @@ public: WriteState WritePixelBlocks(Func aFunc) { MOZ_ASSERT(mHead, "Use before configured!"); - return mHead->WritePixelBlocks(Forward(aFunc)); + return mHead->WritePixelBlocks(std::forward(aFunc)); } /** @@ -667,7 +667,7 @@ public: WriteState WritePixelsToRow(Func aFunc) { MOZ_ASSERT(mHead, "Use before configured!"); - return mHead->WritePixelsToRow(Forward(aFunc)); + return mHead->WritePixelsToRow(std::forward(aFunc)); } /** diff --git a/image/test/gtest/TestADAM7InterpolatingFilter.cpp b/image/test/gtest/TestADAM7InterpolatingFilter.cpp index af69cb410fcc..1bd98218ced6 100644 --- a/image/test/gtest/TestADAM7InterpolatingFilter.cpp +++ b/image/test/gtest/TestADAM7InterpolatingFilter.cpp @@ -31,7 +31,7 @@ WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc) RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(bool(decoder)); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), ADAM7InterpolatingConfig { }, SurfaceConfig { decoder, aSize, SurfaceFormat::B8G8R8A8, false }); diff --git a/image/test/gtest/TestDeinterlacingFilter.cpp b/image/test/gtest/TestDeinterlacingFilter.cpp index 82637bbf7149..55b998544b15 100644 --- a/image/test/gtest/TestDeinterlacingFilter.cpp +++ b/image/test/gtest/TestDeinterlacingFilter.cpp @@ -26,7 +26,7 @@ WithDeinterlacingFilter(const IntSize& aSize, RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(bool(decoder)); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), DeinterlacingConfig { aProgressiveDisplay }, SurfaceConfig { decoder, aSize, SurfaceFormat::B8G8R8A8, false }); @@ -39,7 +39,7 @@ WithPalettedDeinterlacingFilter(const IntSize& aSize, RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(decoder != nullptr); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), DeinterlacingConfig { /* mProgressiveDisplay = */ true }, PalettedSurfaceConfig { decoder, aSize, IntRect(0, 0, 100, 100), diff --git a/image/test/gtest/TestDownscalingFilter.cpp b/image/test/gtest/TestDownscalingFilter.cpp index d7aa0ead2a30..3be916f40434 100644 --- a/image/test/gtest/TestDownscalingFilter.cpp +++ b/image/test/gtest/TestDownscalingFilter.cpp @@ -26,7 +26,7 @@ WithDownscalingFilter(const IntSize& aInputSize, RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(decoder != nullptr); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), DownscalingConfig { aInputSize, SurfaceFormat::B8G8R8A8 }, SurfaceConfig { decoder, aOutputSize, diff --git a/image/test/gtest/TestRemoveFrameRectFilter.cpp b/image/test/gtest/TestRemoveFrameRectFilter.cpp index ad1f944fc4a0..108d58dbdbc3 100644 --- a/image/test/gtest/TestRemoveFrameRectFilter.cpp +++ b/image/test/gtest/TestRemoveFrameRectFilter.cpp @@ -26,7 +26,7 @@ WithRemoveFrameRectFilter(const IntSize& aSize, RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(decoder != nullptr); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), RemoveFrameRectConfig { aFrameRect }, SurfaceConfig { decoder, aSize, SurfaceFormat::B8G8R8A8, false }); diff --git a/image/test/gtest/TestSurfaceSink.cpp b/image/test/gtest/TestSurfaceSink.cpp index 0000d7e50d51..857c3b170e2c 100644 --- a/image/test/gtest/TestSurfaceSink.cpp +++ b/image/test/gtest/TestSurfaceSink.cpp @@ -31,7 +31,7 @@ WithSurfaceSink(Func aFunc) const bool flipVertically = Orientation == Orient::FLIP_VERTICALLY; - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), SurfaceConfig { decoder, IntSize(100, 100), SurfaceFormat::B8G8R8A8, flipVertically }); } @@ -42,7 +42,7 @@ WithPalettedSurfaceSink(const IntRect& aFrameRect, Func aFunc) RefPtr decoder = CreateTrivialDecoder(); ASSERT_TRUE(decoder != nullptr); - WithFilterPipeline(decoder, Forward(aFunc), + WithFilterPipeline(decoder, std::forward(aFunc), PalettedSurfaceConfig { decoder, IntSize(100, 100), aFrameRect, SurfaceFormat::B8G8R8A8, 8, false }); diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h index 01a034a2dcb8..e4b0bc175676 100644 --- a/ipc/chromium/src/base/task.h +++ b/ipc/chromium/src/base/task.h @@ -150,7 +150,7 @@ class ScopedRunnableMethodFactory : public RevocableStore { typedef typename ScopedTaskFactory::TaskWrapper TaskWrapper; RefPtr task = new TaskWrapper(this); - task->Init(object_, method, mozilla::MakeTuple(mozilla::Forward(elements)...)); + task->Init(object_, method, mozilla::MakeTuple(std::forward(elements)...)); return task.forget(); } @@ -167,7 +167,7 @@ class ScopedRunnableMethodFactory : public RevocableStore { { obj_ = obj; meth_ = meth; - params_ = mozilla::Forward(params); + params_ = std::forward(params); } NS_IMETHOD Run() override { @@ -280,7 +280,7 @@ class RunnableMethod : public mozilla::CancelableRunnable, : mozilla::CancelableRunnable("RunnableMethod") , obj_(obj) , meth_(meth) - , params_(mozilla::Forward(params)) + , params_(std::forward(params)) { this->RetainCallee(obj_); } @@ -323,7 +323,7 @@ NewRunnableMethod(T* object, Method method, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; RefPtr t = new RunnableMethod(object, method, - mozilla::MakeTuple(mozilla::Forward(args)...)); + mozilla::MakeTuple(std::forward(args)...)); return t.forget(); } @@ -337,7 +337,7 @@ class RunnableFunction : public mozilla::CancelableRunnable { RunnableFunction(const char* name, Function function, Params&& params) : mozilla::CancelableRunnable(name) , function_(function) - , params_(mozilla::Forward(params)) + , params_(std::forward(params)) { } @@ -365,7 +365,7 @@ NewCancelableRunnableFunction(const char* name, Function function, Args&&... arg typedef mozilla::Tuple::Type...> ArgsTuple; RefPtr t = new RunnableFunction(name, function, - mozilla::MakeTuple(mozilla::Forward(args)...)); + mozilla::MakeTuple(std::forward(args)...)); return t.forget(); } @@ -375,7 +375,7 @@ NewRunnableFunction(const char* name, Function function, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; RefPtr t = new RunnableFunction(name, function, - mozilla::MakeTuple(mozilla::Forward(args)...)); + mozilla::MakeTuple(std::forward(args)...)); return t.forget(); } diff --git a/ipc/chromium/src/chrome/common/ipc_message_utils.h b/ipc/chromium/src/chrome/common/ipc_message_utils.h index f77563fb828b..0cc44f24c9eb 100644 --- a/ipc/chromium/src/chrome/common/ipc_message_utils.h +++ b/ipc/chromium/src/chrome/common/ipc_message_utils.h @@ -132,7 +132,7 @@ template static inline void WriteParam(Message* m, P&& p) { ParamTraits::Type> - ::Write(m, mozilla::Forward

(p)); + ::Write(m, std::forward

(p)); } template diff --git a/ipc/glue/IPDLParamTraits.h b/ipc/glue/IPDLParamTraits.h index 1f55b0d72f7b..c2cb59186d06 100644 --- a/ipc/glue/IPDLParamTraits.h +++ b/ipc/glue/IPDLParamTraits.h @@ -31,7 +31,7 @@ struct IPDLParamTraits static_assert(IsSame::Type>::value, "IPDLParamTraits::Write only forwards calls which work via WriteParam"); - IPC::ParamTraits

::Write(aMsg, Forward(aParam)); + IPC::ParamTraits

::Write(aMsg, std::forward(aParam)); } template @@ -61,7 +61,7 @@ WriteIPDLParam(IPC::Message* aMsg, P&& aParam) { IPDLParamTraits::Type> - ::Write(aMsg, aActor, Forward

(aParam)); + ::Write(aMsg, aActor, std::forward

(aParam)); } template diff --git a/ipc/glue/TaskFactory.h b/ipc/glue/TaskFactory.h index 60d360eda965..98585c6e35c0 100644 --- a/ipc/glue/TaskFactory.h +++ b/ipc/glue/TaskFactory.h @@ -33,7 +33,7 @@ private: public: template explicit TaskWrapper(RevocableStore* store, Args&&... args) - : TaskType(mozilla::Forward(args)...) + : TaskType(std::forward(args)...) , revocable_(store) { } @@ -56,20 +56,20 @@ public: { typedef TaskWrapper TaskWrapper; RefPtr task = - new TaskWrapper(this, mozilla::Forward(args)...); + new TaskWrapper(this, std::forward(args)...); return task.forget(); } template inline already_AddRefed NewRunnableMethod(Method method, Args&&... args) { - typedef decltype(base::MakeTuple(mozilla::Forward(args)...)) ArgTuple; + typedef decltype(base::MakeTuple(std::forward(args)...)) ArgTuple; typedef RunnableMethod RunnableMethod; typedef TaskWrapper TaskWrapper; RefPtr task = new TaskWrapper(this, object_, method, - base::MakeTuple(mozilla::Forward(args)...)); + base::MakeTuple(std::forward(args)...)); return task.forget(); } diff --git a/ipc/mscom/ActivationContext.h b/ipc/mscom/ActivationContext.h index 2bd070b9b2cf..7d7df8c59f84 100644 --- a/ipc/mscom/ActivationContext.h +++ b/ipc/mscom/ActivationContext.h @@ -65,7 +65,7 @@ class MOZ_NON_TEMPORARY_CLASS ActivationContextRegion final public: template explicit ActivationContextRegion(Args... aArgs) - : mActCtx(Forward(aArgs)...) + : mActCtx(std::forward(aArgs)...) , mActCookie(0) { Activate(); diff --git a/ipc/mscom/AsyncInvoker.h b/ipc/mscom/AsyncInvoker.h index 66b491b5c164..fea4f8d83ff6 100644 --- a/ipc/mscom/AsyncInvoker.h +++ b/ipc/mscom/AsyncInvoker.h @@ -303,7 +303,7 @@ public: HRESULT Invoke(SyncMethod aSyncMethod, AsyncMethod aAsyncMethod, Args... aArgs) { if (mSyncObj) { - return (mSyncObj->*aSyncMethod)(Forward(aArgs)...); + return (mSyncObj->*aSyncMethod)(std::forward(aArgs)...); } MOZ_ASSERT(mAsyncCall); @@ -317,7 +317,7 @@ public: return E_POINTER; } - return (asyncInterface->*aAsyncMethod)(Forward(aArgs)...); + return (asyncInterface->*aAsyncMethod)(std::forward(aArgs)...); } AsyncInvoker(const AsyncInvoker& aOther) = delete; diff --git a/ipc/mscom/COMPtrHolder.h b/ipc/mscom/COMPtrHolder.h index fef812e433a4..350b5c025845 100644 --- a/ipc/mscom/COMPtrHolder.h +++ b/ipc/mscom/COMPtrHolder.h @@ -36,12 +36,12 @@ public: } explicit COMPtrHolder(COMPtrType&& aPtr) - : mPtr(Forward(aPtr)) + : mPtr(std::forward(aPtr)) { } COMPtrHolder(COMPtrType&& aPtr, const ActivationContext& aActCtx) - : mPtr(Forward(aPtr)) + : mPtr(std::forward(aPtr)) , mActCtx(aActCtx) { } @@ -58,7 +58,7 @@ public: void Set(COMPtrType&& aPtr) { - mPtr = Forward(aPtr); + mPtr = std::forward(aPtr); } void SetActCtx(const ActivationContext& aActCtx) diff --git a/ipc/mscom/MainThreadInvoker.h b/ipc/mscom/MainThreadInvoker.h index 3a739377563e..3aeb958e452b 100644 --- a/ipc/mscom/MainThreadInvoker.h +++ b/ipc/mscom/MainThreadInvoker.h @@ -47,7 +47,7 @@ InvokeOnMainThread(const char* aName, { nsCOMPtr runnable( NewNonOwningRunnableMethod(aName, aObject, aMethod, - Forward(aArgs)...)); + std::forward(aArgs)...)); MainThreadInvoker invoker; return invoker.Invoke(runnable.forget()); diff --git a/ipc/mscom/Registration.cpp b/ipc/mscom/Registration.cpp index c940cf479b2a..61d3dc402e7a 100644 --- a/ipc/mscom/Registration.cpp +++ b/ipc/mscom/Registration.cpp @@ -338,7 +338,7 @@ RegisteredProxy::~RegisteredProxy() RegisteredProxy::RegisteredProxy(RegisteredProxy&& aOther) { - *this = mozilla::Forward(aOther); + *this = std::forward(aOther); } RegisteredProxy& diff --git a/ipc/mscom/oop/Factory.h b/ipc/mscom/oop/Factory.h index 7ac6ceceb255..9aab07d4c956 100644 --- a/ipc/mscom/oop/Factory.h +++ b/ipc/mscom/oop/Factory.h @@ -41,7 +41,7 @@ class MOZ_NONHEAP_CLASS Factory : public IClassFactory template HRESULT DoCreate(HRESULT (*aFnPtr)(IUnknown*, REFIID, void**), Args... args) { - return aFnPtr(mozilla::Forward(args)...); + return aFnPtr(std::forward(args)...); } public: diff --git a/js/public/GCHashTable.h b/js/public/GCHashTable.h index 78775e9cddaf..aafdd0b0e4b8 100644 --- a/js/public/GCHashTable.h +++ b/js/public/GCHashTable.h @@ -191,29 +191,29 @@ class MutableWrappedPtrOperations, Wrapper> template bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map().add(p, mozilla::Forward(k), mozilla::Forward(v)); + return map().add(p, std::forward(k), std::forward(v)); } template bool add(AddPtr& p, KeyInput&& k) { - return map().add(p, mozilla::Forward(k), Map::Value()); + return map().add(p, std::forward(k), Map::Value()); } template bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { return map().relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); + std::forward(k), + std::forward(v)); } template bool put(KeyInput&& k, ValueInput&& v) { - return map().put(mozilla::Forward(k), mozilla::Forward(v)); + return map().put(std::forward(k), std::forward(v)); } template bool putNew(KeyInput&& k, ValueInput&& v) { - return map().putNew(mozilla::Forward(k), mozilla::Forward(v)); + return map().putNew(std::forward(k), std::forward(v)); } }; @@ -336,27 +336,27 @@ class MutableWrappedPtrOperations, Wrapper> template bool add(AddPtr& p, TInput&& t) { - return set().add(p, mozilla::Forward(t)); + return set().add(p, std::forward(t)); } template bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set().relookupOrAdd(p, l, mozilla::Forward(t)); + return set().relookupOrAdd(p, l, std::forward(t)); } template bool put(TInput&& t) { - return set().put(mozilla::Forward(t)); + return set().put(std::forward(t)); } template bool putNew(TInput&& t) { - return set().putNew(mozilla::Forward(t)); + return set().putNew(std::forward(t)); } template bool putNew(const Lookup& l, TInput&& t) { - return set().putNew(l, mozilla::Forward(t)); + return set().putNew(l, std::forward(t)); } }; @@ -380,11 +380,11 @@ class WeakCache> public: template explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), map(mozilla::Forward(args)...), needsBarrier(false) + : WeakCacheBase(zone), map(std::forward(args)...), needsBarrier(false) {} template explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), map(mozilla::Forward(args)...), needsBarrier(false) + : WeakCacheBase(rt), map(std::forward(args)...), needsBarrier(false) {} ~WeakCache() { MOZ_ASSERT(!needsBarrier); @@ -558,32 +558,27 @@ class WeakCache> template bool add(AddPtr& p, KeyInput&& k) { - using mozilla::Forward; - return map.add(p, Forward(k)); + return map.add(p, std::forward(k)); } template bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.add(p, Forward(k), Forward(v)); + return map.add(p, std::forward(k), std::forward(v)); } template bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.relookupOrAdd(p, Forward(k), Forward(v)); + return map.relookupOrAdd(p, std::forward(k), std::forward(v)); } template bool put(KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.put(Forward(k), Forward(v)); + return map.put(std::forward(k), std::forward(v)); } template bool putNew(KeyInput&& k, ValueInput&& v) { - using mozilla::Forward; - return map.putNew(Forward(k), Forward(v)); + return map.putNew(std::forward(k), std::forward(v)); } }; @@ -604,11 +599,11 @@ class WeakCache> template explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), set(mozilla::Forward(args)...), needsBarrier(false) + : WeakCacheBase(zone), set(std::forward(args)...), needsBarrier(false) {} template explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), set(mozilla::Forward(args)...), needsBarrier(false) + : WeakCacheBase(rt), set(std::forward(args)...), needsBarrier(false) {} size_t sweep() override { @@ -775,27 +770,27 @@ class WeakCache> template bool add(AddPtr& p, TInput&& t) { - return set.add(p, mozilla::Forward(t)); + return set.add(p, std::forward(t)); } template bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set.relookupOrAdd(p, l, mozilla::Forward(t)); + return set.relookupOrAdd(p, l, std::forward(t)); } template bool put(TInput&& t) { - return set.put(mozilla::Forward(t)); + return set.put(std::forward(t)); } template bool putNew(TInput&& t) { - return set.putNew(mozilla::Forward(t)); + return set.putNew(std::forward(t)); } template bool putNew(const Lookup& l, TInput&& t) { - return set.putNew(l, mozilla::Forward(t)); + return set.putNew(l, std::forward(t)); } }; diff --git a/js/public/GCVector.h b/js/public/GCVector.h index 45d2f046ccd5..7f55fd682ba2 100644 --- a/js/public/GCVector.h +++ b/js/public/GCVector.h @@ -76,17 +76,17 @@ class GCVector void clear() { return vector.clear(); } void clearAndFree() { return vector.clearAndFree(); } - template bool append(U&& item) { return vector.append(mozilla::Forward(item)); } + template bool append(U&& item) { return vector.append(std::forward(item)); } template MOZ_MUST_USE bool emplaceBack(Args&&... args) { - return vector.emplaceBack(mozilla::Forward(args)...); + return vector.emplaceBack(std::forward(args)...); } template void infallibleAppend(U&& aU) { - return vector.infallibleAppend(mozilla::Forward(aU)); + return vector.infallibleAppend(std::forward(aU)); } void infallibleAppendN(const T& aT, size_t aN) { return vector.infallibleAppendN(aT, aN); @@ -214,10 +214,10 @@ class MutableWrappedPtrOperations, Wrappe void clear() { vec().clear(); } void clearAndFree() { vec().clearAndFree(); } template - MOZ_MUST_USE bool append(U&& aU) { return vec().append(mozilla::Forward(aU)); } + MOZ_MUST_USE bool append(U&& aU) { return vec().append(std::forward(aU)); } template MOZ_MUST_USE bool emplaceBack(Args&&... aArgs) { - return vec().emplaceBack(mozilla::Forward(aArgs...)); + return vec().emplaceBack(std::forward(aArgs...)); } template MOZ_MUST_USE bool appendAll(const U& aU) { return vec().appendAll(aU); } @@ -231,7 +231,7 @@ class MutableWrappedPtrOperations, Wrappe return vec().append(aBegin, aLength); } template void infallibleAppend(U&& aU) { - vec().infallibleAppend(mozilla::Forward(aU)); + vec().infallibleAppend(std::forward(aU)); } void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); } template void infallibleAppend(const U* aBegin, const U* aEnd) { @@ -243,7 +243,7 @@ class MutableWrappedPtrOperations, Wrappe void popBack() { vec().popBack(); } T popCopy() { return vec().popCopy(); } template T* insert(T* aP, U&& aVal) { - return vec().insert(aP, mozilla::Forward(aVal)); + return vec().insert(aP, std::forward(aVal)); } void erase(T* aT) { vec().erase(aT); } void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); } diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 72e9adf77113..16def6c5e0d1 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -155,20 +155,20 @@ class HashMap template MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.add(p, - mozilla::Forward(k), - mozilla::Forward(v)); + std::forward(k), + std::forward(v)); } template MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& k) { - return impl.add(p, mozilla::Forward(k), Value()); + return impl.add(p, std::forward(k), Value()); } template MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { return impl.relookupOrAdd(p, k, - mozilla::Forward(k), - mozilla::Forward(v)); + std::forward(k), + std::forward(v)); } // |all()| returns a Range containing |count()| elements. E.g.: @@ -241,22 +241,22 @@ class HashMap MOZ_MUST_USE bool put(KeyInput&& k, ValueInput&& v) { AddPtr p = lookupForAdd(k); if (p) { - p->value() = mozilla::Forward(v); + p->value() = std::forward(v); return true; } - return add(p, mozilla::Forward(k), mozilla::Forward(v)); + return add(p, std::forward(k), std::forward(v)); } // Like put, but assert that the given key is not already present. template MOZ_MUST_USE bool putNew(KeyInput&& k, ValueInput&& v) { - return impl.putNew(k, mozilla::Forward(k), mozilla::Forward(v)); + return impl.putNew(k, std::forward(k), std::forward(v)); } // Only call this to populate an empty map after reserving space with init(). template void putNewInfallible(KeyInput&& k, ValueInput&& v) { - impl.putNewInfallible(k, mozilla::Forward(k), mozilla::Forward(v)); + impl.putNewInfallible(k, std::forward(k), std::forward(v)); } // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom. @@ -410,12 +410,12 @@ class HashSet template MOZ_MUST_USE bool add(AddPtr& p, U&& u) { - return impl.add(p, mozilla::Forward(u)); + return impl.add(p, std::forward(u)); } template MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, U&& u) { - return impl.relookupOrAdd(p, l, mozilla::Forward(u)); + return impl.relookupOrAdd(p, l, std::forward(u)); } // |all()| returns a Range containing |count()| elements: @@ -487,24 +487,24 @@ class HashSet template MOZ_MUST_USE bool put(U&& u) { AddPtr p = lookupForAdd(u); - return p ? true : add(p, mozilla::Forward(u)); + return p ? true : add(p, std::forward(u)); } // Like put, but assert that the given key is not already present. template MOZ_MUST_USE bool putNew(U&& u) { - return impl.putNew(u, mozilla::Forward(u)); + return impl.putNew(u, std::forward(u)); } template MOZ_MUST_USE bool putNew(const Lookup& l, U&& u) { - return impl.putNew(l, mozilla::Forward(u)); + return impl.putNew(l, std::forward(u)); } // Only call this to populate an empty set after reserving space with init(). template void putNewInfallible(const Lookup& l, U&& u) { - impl.putNewInfallible(l, mozilla::Forward(u)); + impl.putNewInfallible(l, std::forward(u)); } void remove(const Lookup& l) { @@ -712,13 +712,13 @@ struct FallibleHashMethods template static bool HasHash(Lookup&& l) { - return FallibleHashMethods::hasHash(mozilla::Forward(l)); + return FallibleHashMethods::hasHash(std::forward(l)); } template static bool EnsureHash(Lookup&& l) { - return FallibleHashMethods::ensureHash(mozilla::Forward(l)); + return FallibleHashMethods::ensureHash(std::forward(l)); } /*****************************************************************************/ @@ -741,8 +741,8 @@ class HashMapEntry public: template HashMapEntry(KeyInput&& k, ValueInput&& v) - : key_(mozilla::Forward(k)), - value_(mozilla::Forward(v)) + : key_(std::forward(k)), + value_(std::forward(v)) {} HashMapEntry(HashMapEntry&& rhs) @@ -920,7 +920,7 @@ class HashTableEntry { MOZ_ASSERT(!isLive()); keyHash = hn; - new (valuePtr()) T(mozilla::Forward(args)...); + new (valuePtr()) T(std::forward(args)...); MOZ_ASSERT(isLive()); } }; @@ -1729,7 +1729,7 @@ class HashTable : private AllocPolicy keyHash |= sCollisionBit; } - entry->setLive(keyHash, mozilla::Forward(args)...); + entry->setLive(keyHash, std::forward(args)...); entryCount++; #ifdef JS_DEBUG mutationCount++; @@ -1880,7 +1880,7 @@ class HashTable : private AllocPolicy p.entry_ = &findFreeEntry(p.keyHash); } - p.entry_->setLive(p.keyHash, mozilla::Forward(args)...); + p.entry_->setLive(p.keyHash, std::forward(args)...); entryCount++; #ifdef JS_DEBUG mutationCount++; @@ -1897,7 +1897,7 @@ class HashTable : private AllocPolicy { MOZ_ASSERT(!lookup(l).found()); mozilla::ReentrancyGuard g(*this); - putNewInfallibleInternal(l, mozilla::Forward(args)...); + putNewInfallibleInternal(l, std::forward(args)...); } // Note: |l| may be alias arguments in |args|, so this function must take @@ -1914,7 +1914,7 @@ class HashTable : private AllocPolicy if (checkOverloaded() == RehashFailed) return false; - putNewInfallible(l, mozilla::Forward(args)...); + putNewInfallible(l, std::forward(args)...); return true; } @@ -1936,7 +1936,7 @@ class HashTable : private AllocPolicy MOZ_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed p.entry_ = &lookup(l, p.keyHash, sCollisionBit); } - return p.found() || add(p, mozilla::Forward(args)...); + return p.found() || add(p, std::forward(args)...); } void remove(Ptr p) diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 8a89d0a5ac03..e40725e47e7e 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -347,12 +347,12 @@ class JS_FRIEND_API(GCCellPtr) template auto DispatchTyped(F f, GCCellPtr thing, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) + -> decltype(f(static_cast(nullptr), std::forward(args)...)) { switch (thing.kind()) { #define JS_EXPAND_DEF(name, type, _) \ case JS::TraceKind::name: \ - return f(&thing.as(), mozilla::Forward(args)...); + return f(&thing.as(), std::forward(args)...); JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF default: diff --git a/js/public/Id.h b/js/public/Id.h index 0854d7c5171a..d0c9b1988ee6 100644 --- a/js/public/Id.h +++ b/js/public/Id.h @@ -229,12 +229,12 @@ struct BarrierMethods template auto DispatchTyped(F f, const jsid& id, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) + -> decltype(f(static_cast(nullptr), std::forward(args)...)) { if (JSID_IS_STRING(id)) - return f(JSID_TO_STRING(id), mozilla::Forward(args)...); + return f(JSID_TO_STRING(id), std::forward(args)...); if (JSID_IS_SYMBOL(id)) - return f(JSID_TO_SYMBOL(id), mozilla::Forward(args)...); + return f(JSID_TO_SYMBOL(id), std::forward(args)...); MOZ_ASSERT(!JSID_IS_GCTHING(id)); return F::defaultValue(id); } diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 0aeb139fc339..25826f668ea0 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -768,10 +768,10 @@ template struct FallibleHashMethods> { template static bool hasHash(Lookup&& l) { - return MovableCellHasher::hasHash(mozilla::Forward(l)); + return MovableCellHasher::hasHash(std::forward(l)); } template static bool ensureHash(Lookup&& l) { - return MovableCellHasher::ensureHash(mozilla::Forward(l)); + return MovableCellHasher::ensureHash(std::forward(l)); } }; @@ -801,7 +801,7 @@ class alignas(8) DispatchWrapper template MOZ_IMPLICIT DispatchWrapper(U&& initial) : tracer(&JS::GCPolicy::trace), - storage(mozilla::Forward(initial)) + storage(std::forward(initial)) { } // Mimic a pointer type, so that we can drop into Rooted. @@ -995,7 +995,7 @@ class MOZ_RAII Rooted : public js::RootedBase> template Rooted(const RootingContext& cx, S&& initial) - : ptr(mozilla::Forward(initial)) + : ptr(std::forward(initial)) { MOZ_ASSERT(GCPolicy::isValid(ptr)); registerWithRootLists(rootLists(cx)); @@ -1279,14 +1279,14 @@ class PersistentRooted : public js::RootedBase>, template PersistentRooted(RootingContext* cx, U&& initial) - : ptr(mozilla::Forward(initial)) + : ptr(std::forward(initial)) { registerWithRootLists(cx); } template PersistentRooted(JSContext* cx, U&& initial) - : ptr(mozilla::Forward(initial)) + : ptr(std::forward(initial)) { registerWithRootLists(RootingContext::get(cx)); } @@ -1299,7 +1299,7 @@ class PersistentRooted : public js::RootedBase>, template PersistentRooted(JSRuntime* rt, U&& initial) - : ptr(mozilla::Forward(initial)) + : ptr(std::forward(initial)) { registerWithRootLists(rt); } @@ -1329,7 +1329,7 @@ class PersistentRooted : public js::RootedBase>, template void init(JSContext* cx, U&& initial) { - ptr = mozilla::Forward(initial); + ptr = std::forward(initial); registerWithRootLists(RootingContext::get(cx)); } @@ -1360,7 +1360,7 @@ class PersistentRooted : public js::RootedBase>, template void set(U&& value) { MOZ_ASSERT(initialized()); - ptr = mozilla::Forward(value); + ptr = std::forward(value); } detail::MaybeWrapped ptr; diff --git a/js/public/SweepingAPI.h b/js/public/SweepingAPI.h index eed9f7f14073..fed8c57cca79 100644 --- a/js/public/SweepingAPI.h +++ b/js/public/SweepingAPI.h @@ -66,11 +66,11 @@ class WeakCache : protected detail::WeakCacheBase, template explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), cache(mozilla::Forward(args)...) + : WeakCacheBase(zone), cache(std::forward(args)...) {} template explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), cache(mozilla::Forward(args)...) + : WeakCacheBase(rt), cache(std::forward(args)...) {} const T& get() const { return cache; } diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index 719ed7945013..be3f6b36b9ca 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -196,12 +196,12 @@ template <> struct MapTypeToRootKind : public MapTypeToRootKind auto DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) - -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...)) + -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()(std::forward(args)...)) { switch (traceKind) { #define JS_EXPAND_DEF(name, type, _) \ case JS::TraceKind::name: \ - return f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...); + return f. JS_DEPENDENT_TEMPLATE_HINT operator()(std::forward(args)...); JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF default: @@ -213,12 +213,12 @@ DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) template auto DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) + -> decltype(f(static_cast(nullptr), std::forward(args)...)) { switch (traceKind) { #define JS_EXPAND_DEF(name, type, _) \ case JS::TraceKind::name: \ - return f(static_cast(thing), mozilla::Forward(args)...); + return f(static_cast(thing), std::forward(args)...); JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); #undef JS_EXPAND_DEF default: diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 9d0e74827f3b..96fcbdd2b456 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -176,7 +176,6 @@ class StackFrame; namespace JS { namespace ubi { -using mozilla::Forward; using mozilla::Maybe; using mozilla::RangedPtr; using mozilla::Variant; @@ -196,13 +195,13 @@ class JS_PUBLIC_API(AtomOrTwoByteChars) : public Variant - MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(Forward(rhs)) { } + MOZ_IMPLICIT AtomOrTwoByteChars(T&& rhs) : Base(std::forward(rhs)) { } template AtomOrTwoByteChars& operator=(T&& rhs) { MOZ_ASSERT(this != &rhs, "self-move disallowed"); this->~AtomOrTwoByteChars(); - new (this) AtomOrTwoByteChars(Forward(rhs)); + new (this) AtomOrTwoByteChars(std::forward(rhs)); return *this; } diff --git a/js/public/UniquePtr.h b/js/public/UniquePtr.h index 37e14bc5a0c7..cf854cdd2e07 100644 --- a/js/public/UniquePtr.h +++ b/js/public/UniquePtr.h @@ -45,7 +45,7 @@ template typename detail::UniqueSelector::SingleObject MakeUnique(Args&&... aArgs) { - return UniquePtr(js_new(mozilla::Forward(aArgs)...)); + return UniquePtr(js_new(std::forward(aArgs)...)); } template diff --git a/js/public/Utility.h b/js/public/Utility.h index 53297db85c4c..63b8aff9bcc8 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -479,7 +479,7 @@ JS_PUBLIC_API(char*) js_strdup(const char* s); NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ void* memory = ALLOCATOR(sizeof(T)); \ return MOZ_LIKELY(memory) \ - ? new(memory) T(mozilla::Forward(args)...) \ + ? new(memory) T(std::forward(args)...) \ : nullptr; \ } @@ -497,7 +497,7 @@ JS_PUBLIC_API(char*) js_strdup(const char* s); template \ QUALIFIERS mozilla::UniquePtr> \ MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \ - T* ptr = NEWNAME(mozilla::Forward(args)...); \ + T* ptr = NEWNAME(std::forward(args)...); \ return mozilla::UniquePtr>(ptr); \ } diff --git a/js/public/Value.h b/js/public/Value.h index 6a438924e18f..20470b22ba07 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1429,33 +1429,33 @@ class HeapBase : public WrappedPtrOperations auto DispatchTyped(F f, const JS::Value& val, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) + -> decltype(f(static_cast(nullptr), std::forward(args)...)) { if (val.isString()) { JSString* str = val.toString(); MOZ_ASSERT(gc::IsCellPointerValid(str)); - return f(str, mozilla::Forward(args)...); + return f(str, std::forward(args)...); } if (val.isObject()) { JSObject* obj = &val.toObject(); MOZ_ASSERT(gc::IsCellPointerValid(obj)); - return f(obj, mozilla::Forward(args)...); + return f(obj, std::forward(args)...); } if (val.isSymbol()) { JS::Symbol* sym = val.toSymbol(); MOZ_ASSERT(gc::IsCellPointerValid(sym)); - return f(sym, mozilla::Forward(args)...); + return f(sym, std::forward(args)...); } #ifdef ENABLE_BIGINT if (val.isBigInt()) { JS::BigInt* bi = val.toBigInt(); MOZ_ASSERT(gc::IsCellPointerValid(bi)); - return f(bi, mozilla::Forward(args)...); + return f(bi, std::forward(args)...); } #endif if (MOZ_UNLIKELY(val.isPrivateGCThing())) { MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing())); - return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward(args)...); + return DispatchTyped(f, val.toGCCellPtr(), std::forward(args)...); } MOZ_ASSERT(!val.isGCThing()); return F::defaultValue(val); diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 074076464220..1f052be21706 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -31,7 +31,6 @@ using namespace js::frontend; using JS::AutoValueArray; using mozilla::DebugOnly; -using mozilla::Forward; enum ASTType { AST_ERROR = -1, @@ -322,7 +321,7 @@ class NodeBuilder // Recursive loop to store the arguments into args. This eventually // bottoms out in a call to the non-template callbackHelper() above. args[i].set(head); - return callbackHelper(fun, args, i + 1, Forward(tail)...); + return callbackHelper(fun, args, i + 1, std::forward(tail)...); } // Invoke a user-defined callback. The actual signature is: @@ -335,7 +334,7 @@ class NodeBuilder if (!iargs.init(cx, sizeof...(args) - 2 + size_t(saveLoc))) return false; - return callbackHelper(fun, iargs, 0, Forward(args)...); + return callbackHelper(fun, iargs, 0, std::forward(args)...); } // WARNING: Returning a Handle is non-standard, but it works in this case @@ -388,7 +387,7 @@ class NodeBuilder // `name` and `value`. This eventually bottoms out in a call to the // non-template newNodeHelper() above. return defineProperty(obj, name, value) - && newNodeHelper(obj, Forward(rest)...); + && newNodeHelper(obj, std::forward(rest)...); } // Create a node object with "type" and "loc" properties, as well as zero @@ -402,7 +401,7 @@ class NodeBuilder MOZ_MUST_USE bool newNode(ASTType type, TokenPos* pos, Arguments&&... args) { RootedObject node(cx); return createNode(type, pos, &node) && - newNodeHelper(node, Forward(args)...); + newNodeHelper(node, std::forward(args)...); } MOZ_MUST_USE bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos, diff --git a/js/src/ds/Fifo.h b/js/src/ds/Fifo.h index e2571b7383d2..c50674f3934b 100644 --- a/js/src/ds/Fifo.h +++ b/js/src/ds/Fifo.h @@ -124,7 +124,7 @@ class Fifo // |const T&| or a |T&&|. template MOZ_MUST_USE bool pushBack(U&& u) { - if (!rear_.append(mozilla::Forward(u))) + if (!rear_.append(std::forward(u))) return false; fixup(); return true; @@ -133,7 +133,7 @@ class Fifo // Construct a T in-place at the back of the queue. template MOZ_MUST_USE bool emplaceBack(Args&&... args) { - if (!rear_.emplaceBack(mozilla::Forward(args)...)) + if (!rear_.emplaceBack(std::forward(args)...)) return false; fixup(); return true; diff --git a/js/src/ds/InlineTable.h b/js/src/ds/InlineTable.h index 09d41ae004c0..456100e73fdc 100644 --- a/js/src/ds/InlineTable.h +++ b/js/src/ds/InlineTable.h @@ -298,8 +298,8 @@ class InlineTable : private AllocPolicy if (addPtr == inlineStart() + InlineEntries) { if (!switchToTable()) return false; - return table_.putNew(mozilla::Forward(key), - mozilla::Forward(args)...); + return table_.putNew(std::forward(key), + std::forward(args)...); } MOZ_ASSERT(!p.found()); @@ -308,16 +308,16 @@ class InlineTable : private AllocPolicy if (!this->checkSimulatedOOM()) return false; - addPtr->update(mozilla::Forward(key), - mozilla::Forward(args)...); + addPtr->update(std::forward(key), + std::forward(args)...); ++inlCount_; ++inlNext_; return true; } return table_.add(p.tableAddPtr_, - mozilla::Forward(key), - mozilla::Forward(args)...); + std::forward(key), + std::forward(args)...); } void remove(Ptr& p) { @@ -440,8 +440,8 @@ class InlineMap template void update(KeyInput&& key, ValueInput&& value) { - this->key = mozilla::Forward(key); - this->value = mozilla::Forward(value); + this->key = std::forward(key); + this->value = std::forward(value); } MOZ_MUST_USE bool moveTo(Map& map) { @@ -537,17 +537,17 @@ class InlineMap template MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& key, ValueInput&& value) { - return impl_.add(p, mozilla::Forward(key), mozilla::Forward(value)); + return impl_.add(p, std::forward(key), std::forward(value)); } template MOZ_MUST_USE bool put(KeyInput&& key, ValueInput&& value) { AddPtr p = lookupForAdd(key); if (p) { - p->value() = mozilla::Forward(value); + p->value() = std::forward(value); return true; } - return add(p, mozilla::Forward(key), mozilla::Forward(value)); + return add(p, std::forward(key), std::forward(value)); } void remove(Ptr& p) { @@ -579,7 +579,7 @@ class InlineSet template void update(TInput&& key) { - this->key = mozilla::Forward(key); + this->key = std::forward(key); } MOZ_MUST_USE bool moveTo(Set& set) { @@ -668,13 +668,13 @@ class InlineSet template MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(AddPtr& p, TInput&& key) { - return impl_.add(p, mozilla::Forward(key)); + return impl_.add(p, std::forward(key)); } template MOZ_MUST_USE bool put(TInput&& key) { AddPtr p = lookupForAdd(key); - return p ? true : add(p, mozilla::Forward(key)); + return p ? true : add(p, std::forward(key)); } void remove(Ptr& p) { diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 55c32fe1dbd5..dd388cfb41ea 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -606,7 +606,7 @@ class LifoAlloc if (!ptr) return nullptr; - return new (ptr) T(mozilla::Forward(args)...); + return new (ptr) T(std::forward(args)...); } MOZ_ALWAYS_INLINE diff --git a/js/src/ds/OrderedHashTable.h b/js/src/ds/OrderedHashTable.h index f4d17cc26a10..661533648449 100644 --- a/js/src/ds/OrderedHashTable.h +++ b/js/src/ds/OrderedHashTable.h @@ -40,8 +40,6 @@ #include "mozilla/HashFunctions.h" #include "mozilla/Move.h" -using mozilla::Forward; - namespace js { namespace detail { @@ -176,7 +174,7 @@ class OrderedHashTable MOZ_MUST_USE bool put(ElementInput&& element) { HashNumber h = prepareHash(Ops::getKey(element)); if (Data* e = lookup(Ops::getKey(element), h)) { - e->element = Forward(element); + e->element = std::forward(element); return true; } @@ -191,7 +189,7 @@ class OrderedHashTable h >>= hashShift; liveCount++; Data* e = &data[dataLength++]; - new (e) Data(Forward(element), hashTable[h]); + new (e) Data(std::forward(element), hashTable[h]); hashTable[h] = e; return true; } @@ -761,7 +759,7 @@ class OrderedHashMap public: Entry() : key(), value() {} template - Entry(const Key& k, V&& v) : key(k), value(Forward(v)) {} + Entry(const Key& k, V&& v) : key(k), value(std::forward(v)) {} Entry(Entry&& rhs) : key(std::move(rhs.key)), value(std::move(rhs.value)) {} const Key key; @@ -808,7 +806,7 @@ class OrderedHashMap template MOZ_MUST_USE bool put(const Key& key, V&& value) { - return impl.put(Entry(key, Forward(value))); + return impl.put(Entry(key, std::forward(value))); } HashNumber hash(const Key& key) const { return impl.prepareHash(key); } diff --git a/js/src/ds/TraceableFifo.h b/js/src/ds/TraceableFifo.h index 47dd1b76d5ba..4679e179c31c 100644 --- a/js/src/ds/TraceableFifo.h +++ b/js/src/ds/TraceableFifo.h @@ -74,9 +74,9 @@ class MutableWrappedPtrOperations, Wrapp public: T& front() { return fifo().front(); } - template bool pushBack(U&& u) { return fifo().pushBack(mozilla::Forward(u)); } + template bool pushBack(U&& u) { return fifo().pushBack(std::forward(u)); } template bool emplaceBack(Args&&... args) { - return fifo().emplaceBack(mozilla::Forward(args...)); + return fifo().emplaceBack(std::forward(args...)); } void popFront() { fifo().popFront(); } diff --git a/js/src/frontend/EitherParser.h b/js/src/frontend/EitherParser.h index 418971c88bd5..2b6025eb68bd 100644 --- a/js/src/frontend/EitherParser.h +++ b/js/src/frontend/EitherParser.h @@ -46,7 +46,7 @@ struct InvokeMemberFunction public: template explicit InvokeMemberFunction(ActualArgs&&... actualArgs) - : args { mozilla::Forward(actualArgs)... } + : args { std::forward(actualArgs)... } {} template diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 16d670677d63..688286b722ba 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -6252,7 +6252,7 @@ struct IncrementalIter : maybeIter(maybeIter) { if (maybeIter.isNothing()) - maybeIter.emplace(mozilla::Forward(args)...); + maybeIter.emplace(std::forward(args)...); } ~IncrementalIter() { diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 5676747147ee..e0af9a40adf0 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1466,12 +1466,12 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar if (clasp->isTrace(InlineTypedObject::obj_trace)) { Shape** pshape = obj->as().addressOfShapeFromGC(); - f(pshape, mozilla::Forward(args)...); + f(pshape, std::forward(args)...); InlineTypedObject& tobj = obj->as(); if (tobj.typeDescr().hasTraceList()) { VisitTraceList(f, tobj.typeDescr().traceList(), tobj.inlineTypedMemForGC(), - mozilla::Forward(args)...); + std::forward(args)...); } return nullptr; @@ -1480,7 +1480,7 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar if (clasp == &UnboxedPlainObject::class_) { JSObject** pexpando = obj->as().addressOfExpando(); if (*pexpando) - f(pexpando, mozilla::Forward(args)...); + f(pexpando, std::forward(args)...); UnboxedPlainObject& unboxed = obj->as(); const UnboxedLayout& layout = check == CheckGeneration::DoChecks @@ -1488,7 +1488,7 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar : unboxed.layoutDontCheckGeneration(); if (layout.traceList()) { VisitTraceList(f, layout.traceList(), unboxed.data(), - mozilla::Forward(args)...); + std::forward(args)...); } return nullptr; @@ -1506,19 +1506,19 @@ static void VisitTraceList(F f, const int32_t* traceList, uint8_t* memory, Args&&... args) { while (*traceList != -1) { - f(reinterpret_cast(memory + *traceList), mozilla::Forward(args)...); + f(reinterpret_cast(memory + *traceList), std::forward(args)...); traceList++; } traceList++; while (*traceList != -1) { JSObject** objp = reinterpret_cast(memory + *traceList); if (*objp) - f(objp, mozilla::Forward(args)...); + f(objp, std::forward(args)...); traceList++; } traceList++; while (*traceList != -1) { - f(reinterpret_cast(memory + *traceList), mozilla::Forward(args)...); + f(reinterpret_cast(memory + *traceList), std::forward(args)...); traceList++; } } diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index d6fdfcf857b7..66848b3454ab 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -207,7 +207,7 @@ struct Zone : public JS::shadow::Zone, // in gc/GC-inl.h for the possible arguments and documentation. template js::gc::ZoneCellIter cellIter(Args&&... args) { - return js::gc::ZoneCellIter(const_cast(this), mozilla::Forward(args)...); + return js::gc::ZoneCellIter(const_cast(this), std::forward(args)...); } MOZ_MUST_USE void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, diff --git a/js/src/jit/IonControlFlow.h b/js/src/jit/IonControlFlow.h index bf907f13a939..fee8142ad719 100644 --- a/js/src/jit/IonControlFlow.h +++ b/js/src/jit/IonControlFlow.h @@ -25,12 +25,12 @@ class CFGControlInstruction; #define TRIVIAL_CFG_NEW_WRAPPERS \ template \ static CFGThisOpcode* New(TempAllocator& alloc, Args&&... args) { \ - return new(alloc) CFGThisOpcode(mozilla::Forward(args)...); \ + return new(alloc) CFGThisOpcode(std::forward(args)...); \ } \ template \ static CFGThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args) \ { \ - return new(alloc) CFGThisOpcode(mozilla::Forward(args)...); \ + return new(alloc) CFGThisOpcode(std::forward(args)...); \ } class CFGSpace diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 25a5c195df6c..e90b500de415 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1251,23 +1251,23 @@ class MInstruction #define TRIVIAL_NEW_WRAPPERS \ template \ static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { \ - return new(alloc) MThisOpcode(mozilla::Forward(args)...); \ + return new(alloc) MThisOpcode(std::forward(args)...); \ } \ template \ static MThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args) \ { \ - return new(alloc) MThisOpcode(mozilla::Forward(args)...); \ + return new(alloc) MThisOpcode(std::forward(args)...); \ } #define TRIVIAL_NEW_WRAPPERS_WITH_ALLOC \ template \ static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { \ - return new(alloc) MThisOpcode(alloc, mozilla::Forward(args)...); \ + return new(alloc) MThisOpcode(alloc, std::forward(args)...); \ } \ template \ static MThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args) \ { \ - return new(alloc) MThisOpcode(alloc, mozilla::Forward(args)...); \ + return new(alloc) MThisOpcode(alloc, std::forward(args)...); \ } // These macros are used as a syntactic sugar for writting getOperand diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 860663d2eb21..43aa29ebae32 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -536,7 +536,7 @@ class ICStub static T* New(JSContext* cx, ICStubSpace* space, JitCode* code, Args&&... args) { if (!code) return nullptr; - T* result = space->allocate(code, mozilla::Forward(args)...); + T* result = space->allocate(code, std::forward(args)...); if (!result) ReportOutOfMemory(cx); return result; @@ -1130,7 +1130,7 @@ class ICStubCompiler protected: template T* newStub(Args&&... args) { - return ICStub::New(cx, mozilla::Forward(args)...); + return ICStub::New(cx, std::forward(args)...); } public: diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 1b618f07719b..05adfea10ea2 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -927,7 +927,7 @@ class AssemblerShared template void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, Args&&... args) { enoughMemory_ &= callSites_.emplaceBack(desc, retAddr.offset()); - enoughMemory_ &= callSiteTargets_.emplaceBack(mozilla::Forward(args)...); + enoughMemory_ &= callSiteTargets_.emplaceBack(std::forward(args)...); } void append(wasm::Trap trap, wasm::TrapSite site) { enoughMemory_ &= trapSites_[trap].append(site); diff --git a/js/src/jit/shared/CodeGenerator-shared.h b/js/src/jit/shared/CodeGenerator-shared.h index 088b73015c7f..958d217b7d3d 100644 --- a/js/src/jit/shared/CodeGenerator-shared.h +++ b/js/src/jit/shared/CodeGenerator-shared.h @@ -653,8 +653,8 @@ class ArgSeq : public ArgSeq public: template explicit ArgSeq(ProvidedHead&& head, ProvidedTail&&... tail) - : ArgSeq(mozilla::Forward(tail)...), - head_(mozilla::Forward(head)) + : ArgSeq(std::forward(tail)...), + head_(std::forward(head)) { } // Arguments are pushed in reverse order, from last argument to first @@ -669,7 +669,7 @@ template inline ArgSeq ArgList(ArgTypes&&... args) { - return ArgSeq(mozilla::Forward(args)...); + return ArgSeq(std::forward(args)...); } // Store wrappers, to generate the right move of data after the VM call. diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index 7036e2b1bcd6..844d3a01ec2f 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -480,7 +480,7 @@ LIRGeneratorShared::allocateVariadic(uint32_t numOperands, Args&&... args) return nullptr; LClass* ins = static_cast(buf); - new(ins) LClass(numOperands, mozilla::Forward(args)...); + new(ins) LClass(numOperands, std::forward(args)...); ins->initOperandsOffset(sizeof(LClass)); diff --git a/js/src/threading/ExclusiveData.h b/js/src/threading/ExclusiveData.h index 47e10b58ae86..d64e854d4a80 100644 --- a/js/src/threading/ExclusiveData.h +++ b/js/src/threading/ExclusiveData.h @@ -99,7 +99,7 @@ class ExclusiveData template explicit ExclusiveData(const MutexId& id, U&& u) : lock_(id), - value_(mozilla::Forward(u)) + value_(std::forward(u)) {} /** @@ -108,7 +108,7 @@ class ExclusiveData template explicit ExclusiveData(const MutexId& id, Args&&... args) : lock_(id), - value_(mozilla::Forward(args)...) + value_(std::forward(args)...) {} ExclusiveData(ExclusiveData&& rhs) @@ -196,12 +196,12 @@ class ExclusiveWaitableData : public ExclusiveData public: template explicit ExclusiveWaitableData(const MutexId& id, U&& u) - : Base(id, mozilla::Forward(u)) + : Base(id, std::forward(u)) {} template explicit ExclusiveWaitableData(const MutexId& id, Args&&... args) - : Base(id, mozilla::Forward(args)...) + : Base(id, std::forward(args)...) {} class MOZ_STACK_CLASS Guard : public ExclusiveData::Guard diff --git a/js/src/threading/ProtectedData.h b/js/src/threading/ProtectedData.h index b017ec71d75c..7e3d895c07e1 100644 --- a/js/src/threading/ProtectedData.h +++ b/js/src/threading/ProtectedData.h @@ -72,7 +72,7 @@ class ProtectedData public: template explicit ProtectedData(const Check& check, Args&&... args) - : value(mozilla::Forward(args)...) + : value(std::forward(args)...) #ifdef JS_HAS_PROTECTED_DATA_CHECKS , check(check) #endif @@ -136,7 +136,7 @@ class ProtectedDataNoCheckArgs : public ProtectedData public: template explicit ProtectedDataNoCheckArgs(Args&&... args) - : ProtectedData(Check(), mozilla::Forward(args)...) + : ProtectedData(Check(), std::forward(args)...) {} template @@ -152,7 +152,7 @@ class ProtectedDataZoneArg : public ProtectedData public: template explicit ProtectedDataZoneArg(JS::Zone* zone, Args&&... args) - : ProtectedData(Check(zone), mozilla::Forward(args)...) + : ProtectedData(Check(zone), std::forward(args)...) {} template @@ -315,7 +315,7 @@ class ProtectedDataWriteOnce public: template explicit ProtectedDataWriteOnce(Args&&... args) - : value(mozilla::Forward(args)...) + : value(std::forward(args)...) #ifdef JS_HAS_PROTECTED_DATA_CHECKS , nwrites(0) #endif diff --git a/js/src/threading/Thread.h b/js/src/threading/Thread.h index cc9aa53c31f8..ab3defc136ba 100644 --- a/js/src/threading/Thread.h +++ b/js/src/threading/Thread.h @@ -101,7 +101,7 @@ public: explicit Thread(O&& options = Options()) : idMutex_(mutexid::ThreadId) , id_(Id()) - , options_(mozilla::Forward(options)) + , options_(std::forward(options)) { MOZ_ASSERT(js::IsInitialized()); } @@ -117,8 +117,8 @@ public: MOZ_RELEASE_ASSERT(id_ == Id()); using Trampoline = detail::ThreadTrampoline; AutoEnterOOMUnsafeRegion oom; - auto trampoline = js_new(mozilla::Forward(f), - mozilla::Forward(args)...); + auto trampoline = js_new(std::forward(f), + std::forward(args)...); if (!trampoline) oom.crash("js::Thread::init"); return create(Trampoline::Start, trampoline); @@ -225,8 +225,8 @@ public: // even if the class template arguments are correct. template explicit ThreadTrampoline(G&& aG, ArgsT&&... aArgsT) - : f(mozilla::Forward(aG)), - args(mozilla::Forward(aArgsT)...) + : f(std::forward(aG)), + args(std::forward(aArgsT)...) { } diff --git a/js/src/vm/DebuggerMemory.cpp b/js/src/vm/DebuggerMemory.cpp index 943ed11baafe..4269a23f8be6 100644 --- a/js/src/vm/DebuggerMemory.cpp +++ b/js/src/vm/DebuggerMemory.cpp @@ -31,7 +31,6 @@ using namespace js; -using mozilla::Forward; using mozilla::Maybe; using mozilla::Nothing; diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 96305b3aee05..5513cd10622d 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -434,10 +434,10 @@ template <> struct FallibleHashMethods { template static bool hasHash(Lookup&& l) { - return ObjectGroupRealm::NewEntry::hasHash(mozilla::Forward(l)); + return ObjectGroupRealm::NewEntry::hasHash(std::forward(l)); } template static bool ensureHash(Lookup&& l) { - return ObjectGroupRealm::NewEntry::ensureHash(mozilla::Forward(l)); + return ObjectGroupRealm::NewEntry::ensureHash(std::forward(l)); } }; } // namespace js diff --git a/js/src/vm/SavedFrame.h b/js/src/vm/SavedFrame.h index d3f53f99d46b..777e3b8e6cfb 100644 --- a/js/src/vm/SavedFrame.h +++ b/js/src/vm/SavedFrame.h @@ -176,10 +176,10 @@ template <> struct FallibleHashMethods { template static bool hasHash(Lookup&& l) { - return SavedFrame::HashPolicy::hasHash(mozilla::Forward(l)); + return SavedFrame::HashPolicy::hasHash(std::forward(l)); } template static bool ensureHash(Lookup&& l) { - return SavedFrame::HashPolicy::ensureHash(mozilla::Forward(l)); + return SavedFrame::HashPolicy::ensureHash(std::forward(l)); } }; diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h index ee13f146ef76..564aba4fa403 100644 --- a/js/src/vm/TaggedProto.h +++ b/js/src/vm/TaggedProto.h @@ -137,10 +137,10 @@ class WrappedPtrOperations template auto DispatchTyped(F f, const TaggedProto& proto, Args&&... args) - -> decltype(f(static_cast(nullptr), mozilla::Forward(args)...)) + -> decltype(f(static_cast(nullptr), std::forward(args)...)) { if (proto.isObject()) - return f(proto.toObject(), mozilla::Forward(args)...); + return f(proto.toObject(), std::forward(args)...); return F::defaultValue(proto); } diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index 20f04ac864bb..ef1869e716dc 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -2308,7 +2308,7 @@ class BaseCompiler final : public BaseCompilerInterface template void push(Args&&... args) { - stk_.infallibleEmplaceBack(Stk(Forward(args)...)); + stk_.infallibleEmplaceBack(Stk(std::forward(args)...)); } void pushConstRef(intptr_t v) { diff --git a/js/xpconnect/loader/ScriptPreloader.cpp b/js/xpconnect/loader/ScriptPreloader.cpp index 1d565999c813..4a88bf62ea1e 100644 --- a/js/xpconnect/loader/ScriptPreloader.cpp +++ b/js/xpconnect/loader/ScriptPreloader.cpp @@ -809,7 +809,7 @@ ScriptPreloader::NoteScript(const nsCString& url, const nsCString& cachePath, MOZ_ASSERT(!script->HasArray()); script->mSize = xdrData.Length(); - script->mXDRData.construct>(Forward>(xdrData)); + script->mXDRData.construct>(std::forward>(xdrData)); auto& data = script->Array(); script->mXDRRange.emplace(data.Elements(), data.Length()); diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h index fb9ebee43634..f0577d7eacaf 100644 --- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -2011,7 +2011,7 @@ template MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, Args&&... aArgs) { - T* item = new (aBuilder) T(aBuilder, mozilla::Forward(aArgs)...); + T* item = new (aBuilder) T(aBuilder, std::forward(aArgs)...); const mozilla::SmallPointerArray& array = item->Frame()->DisplayItemData(); diff --git a/media/mtransport/runnable_utils.h b/media/mtransport/runnable_utils.h index 2248d676cbb2..a41f6526da08 100644 --- a/media/mtransport/runnable_utils.h +++ b/media/mtransport/runnable_utils.h @@ -96,7 +96,7 @@ public: // |explicit| to pacify static analysis when there are no |args|. template explicit runnable_args_func(FunType f, Arguments&&... args) - : mFunc(f), mArgs(Forward(args)...) + : mFunc(f), mArgs(std::forward(args)...) {} NS_IMETHOD Run() override { @@ -113,7 +113,7 @@ template runnable_args_func::Type...>* WrapRunnableNM(FunType f, Args&&... args) { - return new runnable_args_func::Type...>(f, Forward(args)...); + return new runnable_args_func::Type...>(f, std::forward(args)...); } template @@ -122,7 +122,7 @@ class runnable_args_func_ret : public detail::runnable_args_base runnable_args_func_ret(Ret* ret, FunType f, Arguments&&... args) - : mReturn(ret), mFunc(f), mArgs(Forward(args)...) + : mReturn(ret), mFunc(f), mArgs(std::forward(args)...) {} NS_IMETHOD Run() override { @@ -140,7 +140,7 @@ template runnable_args_func_ret::Type...>* WrapRunnableNMRet(R* ret, FunType f, Args&&... args) { - return new runnable_args_func_ret::Type...>(ret, f, Forward(args)...); + return new runnable_args_func_ret::Type...>(ret, f, std::forward(args)...); } template @@ -149,7 +149,7 @@ class runnable_args_memfn : public detail::runnable_args_base public: template runnable_args_memfn(Class obj, M method, Arguments&&... args) - : mObj(obj), mMethod(method), mArgs(Forward(args)...) + : mObj(obj), mMethod(method), mArgs(std::forward(args)...) {} NS_IMETHOD Run() override { @@ -167,7 +167,7 @@ template runnable_args_memfn::Type...>* WrapRunnable(Class obj, M method, Args&&... args) { - return new runnable_args_memfn::Type...>(obj, method, Forward(args)...); + return new runnable_args_memfn::Type...>(obj, method, std::forward(args)...); } template @@ -176,7 +176,7 @@ class runnable_args_memfn_ret : public detail::runnable_args_base runnable_args_memfn_ret(Ret* ret, Class obj, M method, Arguments... args) - : mReturn(ret), mObj(obj), mMethod(method), mArgs(Forward(args)...) + : mReturn(ret), mObj(obj), mMethod(method), mArgs(std::forward(args)...) {} NS_IMETHOD Run() override { @@ -195,7 +195,7 @@ template runnable_args_memfn_ret::Type...>* WrapRunnableRet(R* ret, Class obj, M method, Args&&... args) { - return new runnable_args_memfn_ret::Type...>(ret, obj, method, Forward(args)...); + return new runnable_args_memfn_ret::Type...>(ret, obj, method, std::forward(args)...); } static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base *runnable, uint32_t flags) { diff --git a/mfbt/Array.h b/mfbt/Array.h index 1636b0113380..051d2f706dff 100644 --- a/mfbt/Array.h +++ b/mfbt/Array.h @@ -28,7 +28,7 @@ public: template MOZ_IMPLICIT Array(Args&&... aArgs) - : mArr{mozilla::Forward(aArgs)...} + : mArr{std::forward(aArgs)...} { static_assert(sizeof...(aArgs) == Length, "The number of arguments should be equal to the template parameter Length"); diff --git a/mfbt/EnumeratedArray.h b/mfbt/EnumeratedArray.h index 292cfebb06bb..f0f71a3d79b8 100644 --- a/mfbt/EnumeratedArray.h +++ b/mfbt/EnumeratedArray.h @@ -56,7 +56,7 @@ public: template MOZ_IMPLICIT EnumeratedArray(Args&&... aArgs) - : mArray{mozilla::Forward(aArgs)...} + : mArray{std::forward(aArgs)...} {} explicit EnumeratedArray(const EnumeratedArray& aOther) diff --git a/mfbt/LinkedList.h b/mfbt/LinkedList.h index a648fa52d825..e979156a9fa8 100644 --- a/mfbt/LinkedList.h +++ b/mfbt/LinkedList.h @@ -659,7 +659,7 @@ public: AutoCleanLinkedList& operator=(AutoCleanLinkedList&& aOther) { - LinkedList::operator=(Forward>(aOther)); + LinkedList::operator=(std::forward>(aOther)); return *this; } diff --git a/mfbt/Maybe.h b/mfbt/Maybe.h index 39e1446903a9..f443b0a79117 100644 --- a/mfbt/Maybe.h +++ b/mfbt/Maybe.h @@ -327,7 +327,7 @@ public: if (isSome()) { return ref(); } - return Forward(aDefault); + return std::forward(aDefault); } /* @@ -596,7 +596,7 @@ void Maybe::emplace(Args&&... aArgs) { MOZ_DIAGNOSTIC_ASSERT(!mIsSome); - ::new (KnownNotNull, data()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(std::forward(aArgs)...); mIsSome = true; } @@ -617,7 +617,7 @@ Maybe Some(T&& aValue) { Maybe value; - value.emplace(Forward(aValue)); + value.emplace(std::forward(aValue)); return value; } diff --git a/mfbt/MaybeOneOf.h b/mfbt/MaybeOneOf.h index 47983082b410..7e59f1e97874 100644 --- a/mfbt/MaybeOneOf.h +++ b/mfbt/MaybeOneOf.h @@ -106,7 +106,7 @@ public: { MOZ_ASSERT(state == None); state = Type2State::result; - ::new (KnownNotNull, data()) T(Forward(aArgs)...); + ::new (KnownNotNull, data()) T(std::forward(aArgs)...); } template diff --git a/mfbt/Move.h b/mfbt/Move.h index 29b68e0f7f9c..856ab44c4a8b 100644 --- a/mfbt/Move.h +++ b/mfbt/Move.h @@ -137,7 +137,7 @@ namespace mozilla { * template like so[0]: * * template - * C::C(XArg&& x, YArg&& y) : x(Forward(x)), y(Forward(y)) { } + * C::C(XArg&& x, YArg&& y) : x(std::forward(x)), y(std::forward(y)) { } * * ("'Don't Repeat Yourself'? What's that?") * @@ -165,7 +165,7 @@ namespace mozilla { * collapses to 'Y&'. Because the arguments are declared as rvalue references * to template arguments, the lvalue-ness "shines through" where present. * - * Then, the 'Forward' function --- you must invoke 'Forward' with its type + * Then, the 'std::forward' function --- you must invoke 'Forward' with its type * argument --- returns an lvalue reference or an rvalue reference to its * argument, depending on what T is. In our unified constructor definition, that * means that we'll invoke either the copy or move constructors for x and y, @@ -194,26 +194,6 @@ namespace mozilla { * C(tmp, 0); // OK: tmp not a bit-field */ -/** - * These two overloads are identical to std::forward(); they are necessary until - * our stlport supports std::forward(). - */ -template -inline T&& -Forward(typename RemoveReference::Type& aX) -{ - return static_cast(aX); -} - -template -inline T&& -Forward(typename RemoveReference::Type&& aX) -{ - static_assert(!IsLvalueReference::value, - "misuse of Forward detected! try the other overload"); - return static_cast(aX); -} - /** Swap |aX| and |aY| using move-construction if possible. */ template inline void diff --git a/mfbt/NotNull.h b/mfbt/NotNull.h index 6eed1ed395f4..479dd2bc2518 100644 --- a/mfbt/NotNull.h +++ b/mfbt/NotNull.h @@ -200,7 +200,7 @@ MakeNotNull(Args&&... aArgs) using Pointee = typename detail::PointedTo::NonConstType; static_assert(!IsArray::value, "MakeNotNull cannot construct an array"); - return NotNull(new Pointee(Forward(aArgs)...)); + return NotNull(new Pointee(std::forward(aArgs)...)); } // Compare two NotNulls. diff --git a/mfbt/Pair.h b/mfbt/Pair.h index 7cc92a9adb23..1197f2f8894b 100644 --- a/mfbt/Pair.h +++ b/mfbt/Pair.h @@ -41,8 +41,8 @@ struct PairHelper protected: template PairHelper(AArg&& aA, BArg&& aB) - : mFirstA(Forward(aA)), - mSecondB(Forward(aB)) + : mFirstA(std::forward(aA)), + mSecondB(std::forward(aB)) {} A& first() { return mFirstA; } @@ -67,8 +67,8 @@ struct PairHelper : private B protected: template PairHelper(AArg&& aA, BArg&& aB) - : B(Forward(aB)), - mFirstA(Forward(aA)) + : B(std::forward(aB)), + mFirstA(std::forward(aA)) {} A& first() { return mFirstA; } @@ -92,8 +92,8 @@ struct PairHelper : private A protected: template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - mSecondB(Forward(aB)) + : A(std::forward(aA)), + mSecondB(std::forward(aB)) {} A& first() { return *this; } @@ -117,8 +117,8 @@ struct PairHelper : private A, private B protected: template PairHelper(AArg&& aA, BArg&& aB) - : A(Forward(aA)), - B(Forward(aB)) + : A(std::forward(aA)), + B(std::forward(aB)) {} A& first() { return static_cast(*this); } @@ -157,7 +157,7 @@ struct Pair public: template Pair(AArg&& aA, BArg&& aB) - : Base(Forward(aA), Forward(aB)) + : Base(std::forward(aA), std::forward(aB)) {} Pair(Pair&& aOther) @@ -210,8 +210,8 @@ MakePair(A&& aA, B&& aB) return Pair::Type>::Type, typename RemoveCV::Type>::Type>( - Forward(aA), - Forward(aB)); + std::forward(aA), + std::forward(aB)); } } // namespace mozilla diff --git a/mfbt/RefPtr.h b/mfbt/RefPtr.h index fe871fe22ce1..4ba2854f1487 100644 --- a/mfbt/RefPtr.h +++ b/mfbt/RefPtr.h @@ -343,7 +343,7 @@ public: template R operator()(ActualArgs&&... aArgs) { - return ((*mRawPtr).*mFunction)(mozilla::Forward(aArgs)...); + return ((*mRawPtr).*mFunction)(std::forward(aArgs)...); } }; @@ -655,7 +655,7 @@ template already_AddRefed MakeAndAddRef(Args&&... aArgs) { - RefPtr p(new T(Forward(aArgs)...)); + RefPtr p(new T(std::forward(aArgs)...)); return p.forget(); } @@ -669,7 +669,7 @@ template RefPtr MakeRefPtr(Args&&... aArgs) { - RefPtr p(new T(Forward(aArgs)...)); + RefPtr p(new T(std::forward(aArgs)...)); return p; } diff --git a/mfbt/Result.h b/mfbt/Result.h index d5aa627ee503..ff8f00c20e9b 100644 --- a/mfbt/Result.h +++ b/mfbt/Result.h @@ -263,9 +263,9 @@ struct IsResult> : TrueType { }; template auto ToResult(Result&& aValue) - -> decltype(Forward>(aValue)) + -> decltype(std::forward>(aValue)) { - return Forward>(aValue); + return std::forward>(aValue); } /** diff --git a/mfbt/SegmentedVector.h b/mfbt/SegmentedVector.h index dd2739990840..be50f64589ac 100644 --- a/mfbt/SegmentedVector.h +++ b/mfbt/SegmentedVector.h @@ -89,7 +89,7 @@ class SegmentedVector : private AllocPolicy // Pre-increment mLength so that the bounds-check in operator[] passes. mLength++; T* elem = &(*this)[mLength - 1]; - new (elem) T(mozilla::Forward(aU)); + new (elem) T(std::forward(aU)); } void PopLast() @@ -175,7 +175,7 @@ public: new (last) Segment(); mSegments.insertBack(last); } - last->Append(mozilla::Forward(aU)); + last->Append(std::forward(aU)); return true; } @@ -184,7 +184,7 @@ public: template void InfallibleAppend(U&& aU) { - bool ok = Append(mozilla::Forward(aU)); + bool ok = Append(std::forward(aU)); MOZ_RELEASE_ASSERT(ok); } diff --git a/mfbt/Span.h b/mfbt/Span.h index 5a94ab471a73..b2102f6cede2 100644 --- a/mfbt/Span.h +++ b/mfbt/Span.h @@ -60,7 +60,7 @@ template inline constexpr T narrow_cast(U&& u) { - return static_cast(mozilla::Forward(u)); + return static_cast(std::forward(u)); } // end gsl_util diff --git a/mfbt/Tuple.h b/mfbt/Tuple.h index 268bd7010b13..d99ea5c7c415 100644 --- a/mfbt/Tuple.h +++ b/mfbt/Tuple.h @@ -139,7 +139,7 @@ struct TupleImpl Group, Group>::value>::Type> explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) - : Base(Forward(aTail)...), mHead(Forward(aHead)) { } + : Base(std::forward(aTail)...), mHead(std::forward(aHead)) { } // Copy and move constructors. // We'd like to use '= default' to implement these, but MSVC 2013's support @@ -149,7 +149,7 @@ struct TupleImpl , mHead(Head(aOther)) {} TupleImpl(TupleImpl&& aOther) : Base(std::move(Tail(aOther))) - , mHead(Forward(Head(aOther))) {} + , mHead(std::forward(Head(aOther))) {} // Assign from a tuple whose elements are convertible to the elements // of this tuple. @@ -225,7 +225,7 @@ public: detail::Group, detail::Group>::value>::Type> explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) - : Impl(Forward(aHead), Forward(aTail)...) { } + : Impl(std::forward(aHead), std::forward(aTail)...) { } Tuple(const Tuple& aOther) : Impl(aOther) { } Tuple(Tuple&& aOther) : Impl(std::move(aOther)) { } @@ -282,17 +282,17 @@ public: detail::Group, detail::Group>::value>::Type> explicit Tuple(AArg&& aA, BArg&& aB) - : Impl(Forward(aA), Forward(aB)) { } + : Impl(std::forward(aA), std::forward(aB)) { } Tuple(const Tuple& aOther) : Impl(aOther) { } Tuple(Tuple&& aOther) : Impl(std::move(aOther)) { } explicit Tuple(const Pair& aOther) : Impl(aOther.first(), aOther.second()) { } - explicit Tuple(Pair&& aOther) : Impl(Forward(aOther.first()), - Forward(aOther.second())) { } + explicit Tuple(Pair&& aOther) : Impl(std::forward(aOther.first()), + std::forward(aOther.second())) { } explicit Tuple(const std::pair& aOther) : Impl(aOther.first, aOther.second) { } - explicit Tuple(std::pair&& aOther) : Impl(Forward(aOther.first), - Forward(aOther.second)) { } + explicit Tuple(std::pair&& aOther) : Impl(std::forward(aOther.first), + std::forward(aOther.second)) { } template Tuple& operator=(const Tuple& aOther) @@ -326,8 +326,8 @@ public: template Tuple& operator=(Pair&& aOther) { - Impl::Head(*this) = Forward(aOther.first()); - Impl::Tail(*this).Head(*this) = Forward(aOther.second()); + Impl::Head(*this) = std::forward(aOther.first()); + Impl::Tail(*this).Head(*this) = std::forward(aOther.second()); return *this; } template @@ -340,8 +340,8 @@ public: template Tuple& operator=(std::pair&& aOther) { - Impl::Head(*this) = Forward(aOther.first); - Impl::Tail(*this).Head(*this) = Forward(aOther.second); + Impl::Head(*this) = std::forward(aOther.first); + Impl::Tail(*this).Head(*this) = std::forward(aOther.second); return *this; } }; @@ -433,7 +433,7 @@ template inline Tuple::Type...> MakeTuple(Elements&&... aElements) { - return Tuple::Type...>(Forward(aElements)...); + return Tuple::Type...>(std::forward(aElements)...); } /** diff --git a/mfbt/UniquePtr.h b/mfbt/UniquePtr.h index 0a9907e8071b..769142403fb0 100644 --- a/mfbt/UniquePtr.h +++ b/mfbt/UniquePtr.h @@ -260,7 +260,7 @@ public: } UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) + : mTuple(aOther.release(), std::forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -281,7 +281,7 @@ public: ? IsSame::value : IsConvertible::value), int>::Type aDummy = 0) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) + : mTuple(aOther.release(), std::forward(aOther.get_deleter())) { } @@ -290,7 +290,7 @@ public: UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - get_deleter() = Forward(aOther.get_deleter()); + get_deleter() = std::forward(aOther.get_deleter()); return *this; } @@ -304,7 +304,7 @@ public: "can't assign from UniquePtr holding an array"); reset(aOther.release()); - get_deleter() = Forward(aOther.get_deleter()); + get_deleter() = std::forward(aOther.get_deleter()); return *this; } @@ -429,7 +429,7 @@ public: = delete; UniquePtr(UniquePtr&& aOther) - : mTuple(aOther.release(), Forward(aOther.get_deleter())) + : mTuple(aOther.release(), std::forward(aOther.get_deleter())) {} MOZ_IMPLICIT @@ -445,7 +445,7 @@ public: UniquePtr& operator=(UniquePtr&& aOther) { reset(aOther.release()); - get_deleter() = Forward(aOther.get_deleter()); + get_deleter() = std::forward(aOther.get_deleter()); return *this; } @@ -677,7 +677,7 @@ template typename detail::UniqueSelector::SingleObject MakeUnique(Args&&... aArgs) { - return UniquePtr(new T(Forward(aArgs)...)); + return UniquePtr(new T(std::forward(aArgs)...)); } template diff --git a/mfbt/UniquePtrExtensions.h b/mfbt/UniquePtrExtensions.h index d94f33eea38d..004f313b9238 100644 --- a/mfbt/UniquePtrExtensions.h +++ b/mfbt/UniquePtrExtensions.h @@ -22,7 +22,7 @@ template typename detail::UniqueSelector::SingleObject MakeUniqueFallible(Args&&... aArgs) { - return UniquePtr(new (fallible) T(Forward(aArgs)...)); + return UniquePtr(new (fallible) T(std::forward(aArgs)...)); } template diff --git a/mfbt/Variant.h b/mfbt/Variant.h index e2c197fd0129..922ed7b14da1 100644 --- a/mfbt/Variant.h +++ b/mfbt/Variant.h @@ -279,7 +279,7 @@ struct AsVariantTemporary template explicit AsVariantTemporary(U&& aValue) - : mValue(Forward(aValue)) + : mValue(std::forward(aValue)) {} AsVariantTemporary(const AsVariantTemporary& aOther) @@ -528,7 +528,7 @@ public: { static_assert(detail::SelectVariantType::count == 1, "Variant can only be selected by type if that type is unique"); - ::new (KnownNotNull, ptr()) T(Forward(aT)); + ::new (KnownNotNull, ptr()) T(std::forward(aT)); } /** @@ -541,7 +541,7 @@ public: MOZ_IMPLICIT Variant(const VariantType&, Args&&... aTs) : tag(Impl::template tag()) { - ::new (KnownNotNull, ptr()) T(Forward(aTs)...); + ::new (KnownNotNull, ptr()) T(std::forward(aTs)...); } /** @@ -556,7 +556,7 @@ public: : tag(N) { using T = typename detail::Nth::Type; - ::new (KnownNotNull, ptr()) T(Forward(aTs)...); + ::new (KnownNotNull, ptr()) T(std::forward(aTs)...); } /** @@ -752,7 +752,7 @@ template detail::AsVariantTemporary AsVariant(T&& aValue) { - return detail::AsVariantTemporary(Forward(aValue)); + return detail::AsVariantTemporary(std::forward(aValue)); } } // namespace mozilla diff --git a/mfbt/Vector.h b/mfbt/Vector.h index bef8a8c4aa90..5df71619a5ef 100644 --- a/mfbt/Vector.h +++ b/mfbt/Vector.h @@ -63,7 +63,7 @@ struct VectorImpl MOZ_NONNULL(1) static inline void new_(T* aDst, Args&&... aArgs) { - new(KnownNotNull, aDst) T(Forward(aArgs)...); + new(KnownNotNull, aDst) T(std::forward(aArgs)...); } /* Destroys constructed objects in the range [aBegin, aEnd). */ @@ -168,7 +168,7 @@ struct VectorImpl // T(args...) will be treated like a C-style cast in the unary case and // allow unsafe conversions. Both forms should be equivalent to an // optimizing compiler. - T temp(Forward(aArgs)...); + T temp(std::forward(aArgs)...); *aDst = temp; } @@ -706,7 +706,7 @@ public: { if (!growByUninitialized(1)) return false; - Impl::new_(&back(), Forward(aArgs)...); + Impl::new_(&back(), std::forward(aArgs)...); return true; } @@ -723,7 +723,7 @@ public: */ template void infallibleAppend(U&& aU) { - internalAppend(Forward(aU)); + internalAppend(std::forward(aU)); } void infallibleAppendN(const T& aT, size_t aN) { @@ -741,7 +741,7 @@ public: void infallibleEmplaceBack(Args&&... aArgs) { infallibleGrowByUninitialized(1); - Impl::new_(&back(), Forward(aArgs)...); + Impl::new_(&back(), std::forward(aArgs)...); } void popBack(); @@ -1277,7 +1277,7 @@ Vector::internalAppend(U&& aU) { MOZ_ASSERT(mLength + 1 <= mTail.mReserved); MOZ_ASSERT(mTail.mReserved <= mTail.mCapacity); - Impl::new_(endNoCheck(), Forward(aU)); + Impl::new_(endNoCheck(), std::forward(aU)); ++mLength; } @@ -1323,7 +1323,7 @@ Vector::insert(T* aP, U&& aVal) MOZ_ASSERT(pos <= mLength); size_t oldLength = mLength; if (pos == oldLength) { - if (!append(Forward(aVal))) { + if (!append(std::forward(aVal))) { return nullptr; } } else { @@ -1334,7 +1334,7 @@ Vector::insert(T* aP, U&& aVal) for (size_t i = oldLength - 1; i > pos; --i) { (*this)[i] = std::move((*this)[i - 1]); } - (*this)[pos] = Forward(aVal); + (*this)[pos] = std::forward(aVal); } return begin() + pos; } @@ -1417,7 +1417,7 @@ Vector::append(U&& aU) mTail.mReserved = mLength + 1; } #endif - internalAppend(Forward(aU)); + internalAppend(std::forward(aU)); return true; } diff --git a/mozglue/misc/DynamicallyLinkedFunctionPtr.h b/mozglue/misc/DynamicallyLinkedFunctionPtr.h index ecfede39384b..5e1e44e19fb5 100644 --- a/mozglue/misc/DynamicallyLinkedFunctionPtr.h +++ b/mozglue/misc/DynamicallyLinkedFunctionPtr.h @@ -54,7 +54,7 @@ public: R operator()(Args... args) const { - return mFunction(mozilla::Forward(args)...); + return mFunction(std::forward(args)...); } explicit operator bool() const diff --git a/mozglue/misc/interceptor/PatcherBase.h b/mozglue/misc/interceptor/PatcherBase.h index 0f57016fd1c9..7d40f1215776 100644 --- a/mozglue/misc/interceptor/PatcherBase.h +++ b/mozglue/misc/interceptor/PatcherBase.h @@ -20,7 +20,7 @@ protected: template explicit WindowsDllPatcherBase(Args... aArgs) - : mVMPolicy(mozilla::Forward(aArgs)...) + : mVMPolicy(std::forward(aArgs)...) { } diff --git a/mozglue/misc/interceptor/PatcherDetour.h b/mozglue/misc/interceptor/PatcherDetour.h index cb9471721872..1a81597a1dae 100644 --- a/mozglue/misc/interceptor/PatcherDetour.h +++ b/mozglue/misc/interceptor/PatcherDetour.h @@ -26,7 +26,7 @@ class WindowsDllDetourPatcher final : public WindowsDllPatcherBase public: template explicit WindowsDllDetourPatcher(Args... aArgs) - : WindowsDllPatcherBase(mozilla::Forward(aArgs)...) + : WindowsDllPatcherBase(std::forward(aArgs)...) { } diff --git a/mozglue/misc/interceptor/PatcherNopSpace.h b/mozglue/misc/interceptor/PatcherNopSpace.h index 496dcdd5ea35..a246558845d5 100644 --- a/mozglue/misc/interceptor/PatcherNopSpace.h +++ b/mozglue/misc/interceptor/PatcherNopSpace.h @@ -23,7 +23,7 @@ class WindowsDllNopSpacePatcher final : public WindowsDllPatcherBase public: template explicit WindowsDllNopSpacePatcher(Args... aArgs) - : WindowsDllPatcherBase(mozilla::Forward(aArgs)...) + : WindowsDllPatcherBase(std::forward(aArgs)...) {} ~WindowsDllNopSpacePatcher() diff --git a/mozglue/misc/interceptor/VMSharingPolicies.h b/mozglue/misc/interceptor/VMSharingPolicies.h index 450c0b383b96..8ceab3be8ab5 100644 --- a/mozglue/misc/interceptor/VMSharingPolicies.h +++ b/mozglue/misc/interceptor/VMSharingPolicies.h @@ -19,7 +19,7 @@ class VMSharingPolicyUnique : public MMPolicy public: template explicit VMSharingPolicyUnique(Args... aArgs) - : MMPolicy(mozilla::Forward(aArgs)...) + : MMPolicy(std::forward(aArgs)...) , mNextChunkIndex(0) { } diff --git a/mozglue/misc/nsWindowsDllInterceptor.h b/mozglue/misc/nsWindowsDllInterceptor.h index bb2ddbce8b76..3020f795fede 100644 --- a/mozglue/misc/nsWindowsDllInterceptor.h +++ b/mozglue/misc/nsWindowsDllInterceptor.h @@ -103,9 +103,9 @@ class WindowsDllInterceptor final public: template explicit WindowsDllInterceptor(Args... aArgs) - : mDetourPatcher(mozilla::Forward(aArgs)...) + : mDetourPatcher(std::forward(aArgs)...) #if defined(_M_IX86) - , mNopSpacePatcher(mozilla::Forward(aArgs)...) + , mNopSpacePatcher(std::forward(aArgs)...) #endif // defined(_M_IX86) , mModule(nullptr) , mNHooks(0) diff --git a/security/sandbox/linux/SandboxOpenedFiles.h b/security/sandbox/linux/SandboxOpenedFiles.h index 43853b542147..b539e0ad2727 100644 --- a/security/sandbox/linux/SandboxOpenedFiles.h +++ b/security/sandbox/linux/SandboxOpenedFiles.h @@ -69,7 +69,7 @@ public: template void Add(Args&&... aArgs) { - mFiles.emplace_back(Forward(aArgs)...); + mFiles.emplace_back(std::forward(aArgs)...); } int GetDesc(const char* aPath) const; diff --git a/toolkit/components/extensions/MatchPattern.h b/toolkit/components/extensions/MatchPattern.h index 547b4bad8139..ea48e2c58da1 100644 --- a/toolkit/components/extensions/MatchPattern.h +++ b/toolkit/components/extensions/MatchPattern.h @@ -346,7 +346,7 @@ protected: private: explicit MatchPatternSet(nsISupports* aParent, ArrayType&& aPatterns) : mParent(aParent) - , mPatterns(Forward(aPatterns)) + , mPatterns(std::forward(aPatterns)) {} nsCOMPtr mParent; diff --git a/toolkit/components/url-classifier/tests/gtest/Common.cpp b/toolkit/components/url-classifier/tests/gtest/Common.cpp index f2344b08d953..e7f25e25dc5b 100644 --- a/toolkit/components/url-classifier/tests/gtest/Common.cpp +++ b/toolkit/components/url-classifier/tests/gtest/Common.cpp @@ -16,7 +16,7 @@ using namespace mozilla::safebrowsing; template void RunTestInNewThread(Function&& aFunction) { nsCOMPtr r = NS_NewRunnableFunction( - "RunTestInNewThread", mozilla::Forward(aFunction)); + "RunTestInNewThread", std::forward(aFunction)); nsCOMPtr testingThread; nsresult rv = NS_NewNamedThread("Testing Thread", getter_AddRefs(testingThread), r); diff --git a/widget/android/jni/Natives.h b/widget/android/jni/Natives.h index 054961a8e8ae..6271c7a5119b 100644 --- a/widget/android/jni/Natives.h +++ b/widget/android/jni/Natives.h @@ -519,7 +519,7 @@ struct Dispatcher { Impl::OnNativeCall(ProxyNativeCall< Impl, typename Traits::Owner, IsStatic, - HasThisArg, Args...>(Forward(args)...)); + HasThisArg, Args...>(std::forward(args)...)); } template( (HasThisArg || !IsStatic) ? thisArg : nullptr, - Forward(args)...); + std::forward(args)...); DispatchToGeckoPriorityQueue( NS_NewRunnableFunction("PriorityNativeCall", std::move(proxy))); } @@ -551,7 +551,7 @@ struct Dispatcher auto proxy = ProxyNativeCall( (HasThisArg || !IsStatic) ? thisArg : nullptr, - Forward(args)...); + std::forward(args)...); NS_DispatchToMainThread( NS_NewRunnableFunction("GeckoNativeCall", std::move(proxy))); } diff --git a/widget/android/nsAppShell.h b/widget/android/nsAppShell.h index 4b63597118b6..cb0f8c2f6fe6 100644 --- a/widget/android/nsAppShell.h +++ b/widget/android/nsAppShell.h @@ -152,7 +152,7 @@ public: typename mozilla::EnableIf::value, void>::Type SyncRunEvent(T&& lambda) { - SyncRunEvent(LambdaEvent(mozilla::Forward(lambda))); + SyncRunEvent(LambdaEvent(std::forward(lambda))); } static already_AddRefed ResolveURI(const nsCString& aUriStr); diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 2b2e4f3e929e..796111ccb3e9 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -145,7 +145,7 @@ public: InstanceType&& aInstance) : Runnable("nsWindowEvent") , mLambda(std::move(aLambda)) - , mInstance(Forward(aInstance)) + , mInstance(std::forward(aInstance)) {} explicit WindowEvent(Lambda&& aLambda) @@ -199,7 +199,7 @@ nsWindow::NativePtr::Attach(Instance aInstance, nsWindow* aWindow, MOZ_ASSERT(!mPtr && !mImpl); Impl* const impl = new Impl( - this, aWindow, mozilla::Forward(aArgs)...); + this, aWindow, std::forward(aArgs)...); mImpl = impl; // CallAttachNative transfers ownership of impl. diff --git a/xpcom/base/nsAutoPtr.h b/xpcom/base/nsAutoPtr.h index 8a16c63fd295..866ddf13b5cd 100644 --- a/xpcom/base/nsAutoPtr.h +++ b/xpcom/base/nsAutoPtr.h @@ -216,7 +216,7 @@ public: template R operator()(ActualArgs&&... aArgs) { - return ((*mRawPtr).*mFunction)(mozilla::Forward(aArgs)...); + return ((*mRawPtr).*mFunction)(std::forward(aArgs)...); } }; diff --git a/xpcom/ds/nsClassHashtable.h b/xpcom/ds/nsClassHashtable.h index 46ccc53a5e6a..1634aee04533 100644 --- a/xpcom/ds/nsClassHashtable.h +++ b/xpcom/ds/nsClassHashtable.h @@ -90,7 +90,7 @@ nsClassHashtable::LookupOrAdd(KeyType aKey, auto count = this->Count(); typename base_type::EntryType* ent = this->PutEntry(aKey); if (count != this->Count()) { - ent->mData = new T(mozilla::Forward(aConstructionArgs)...); + ent->mData = new T(std::forward(aConstructionArgs)...); } return ent->mData; } diff --git a/xpcom/ds/nsTArray.h b/xpcom/ds/nsTArray.h index d6b9fa257f80..5fb5133b0c9c 100644 --- a/xpcom/ds/nsTArray.h +++ b/xpcom/ds/nsTArray.h @@ -538,7 +538,7 @@ public: static_assert(!mozilla::IsSame::value, "For safety, we disallow constructing nsTArray elements " "from E* pointers. See bug 960591."); - new (static_cast(aE)) E(mozilla::Forward(aArg)); + new (static_cast(aE)) E(std::forward(aArg)); } // Invoke the destructor in place. static inline void Destruct(E* aE) { aE->~E(); } @@ -1493,7 +1493,7 @@ public: const mozilla::fallible_t&) { return InsertElementAt(aIndex, - mozilla::Forward(aItem)); + std::forward(aItem)); } // Reconstruct the element at the given index, and return a pointer to the @@ -1558,7 +1558,7 @@ protected: { index_type index = IndexOfFirstElementGt(aItem, aComp); return InsertElementAt( - index, mozilla::Forward(aItem)); + index, std::forward(aItem)); } public: @@ -1568,7 +1568,7 @@ public: const mozilla::fallible_t&) { return InsertElementSorted( - mozilla::Forward(aItem), aComp); + std::forward(aItem), aComp); } // A variation on the InsertElementSorted method defined above. @@ -1578,7 +1578,7 @@ protected: { nsDefaultComparator comp; return InsertElementSorted( - mozilla::Forward(aItem), comp); + std::forward(aItem), comp); } public: @@ -1587,7 +1587,7 @@ public: elem_type* InsertElementSorted(Item&& aItem, const mozilla::fallible_t&) { return InsertElementSorted( - mozilla::Forward(aItem)); + std::forward(aItem)); } // This method appends elements to the end of this array. @@ -1676,7 +1676,7 @@ public: elem_type* AppendElement(Item&& aItem, const mozilla::fallible_t&) { - return AppendElement(mozilla::Forward(aItem)); + return AppendElement(std::forward(aItem)); } // Append new elements without copy-constructing. This is useful to avoid @@ -2236,7 +2236,7 @@ nsTArray_Impl::InsertElementAt(index_type aIndex, Item&& aItem) -> ele this->template ShiftData(aIndex, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type)); elem_type* elem = Elements() + aIndex; - elem_traits::Construct(elem, mozilla::Forward(aItem)); + elem_traits::Construct(elem, std::forward(aItem)); return elem; } @@ -2290,7 +2290,7 @@ nsTArray_Impl::AppendElement(Item&& aItem) -> elem_type* return nullptr; } elem_type* elem = Elements() + Length(); - elem_traits::Construct(elem, mozilla::Forward(aItem)); + elem_traits::Construct(elem, std::forward(aItem)); this->mHdr->mLength += 1; return elem; } diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index 36b4091a15b8..5b88849bb425 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -181,7 +181,7 @@ public: { MOZ_ASSERT(IsNothing()); mValue = Storage(VariantIndex{}, - Forward(aResolveValue)); + std::forward(aResolveValue)); } template @@ -189,14 +189,14 @@ public: { MOZ_ASSERT(IsNothing()); mValue = Storage(VariantIndex{}, - Forward(aRejectValue)); + std::forward(aRejectValue)); } template static ResolveOrRejectValue MakeResolve(ResolveValueType_&& aResolveValue) { ResolveOrRejectValue val; - val.SetResolve(Forward(aResolveValue)); + val.SetResolve(std::forward(aResolveValue)); return val; } @@ -204,7 +204,7 @@ public: static ResolveOrRejectValue MakeReject(RejectValueType_&& aRejectValue) { ResolveOrRejectValue val; - val.SetReject(Forward(aRejectValue)); + val.SetReject(std::forward(aRejectValue)); return val; } @@ -265,7 +265,7 @@ public: CreateAndResolve(ResolveValueType_&& aResolveValue, const char* aResolveSite) { RefPtr p = new MozPromise::Private(aResolveSite); - p->Resolve(Forward(aResolveValue), aResolveSite); + p->Resolve(std::forward(aResolveValue), aResolveSite); return p.forget(); } @@ -274,7 +274,7 @@ public: CreateAndReject(RejectValueType_&& aRejectValue, const char* aRejectSite) { RefPtr p = new MozPromise::Private(aRejectSite); - p->Reject(Forward(aRejectValue), aRejectSite); + p->Reject(std::forward(aRejectValue), aRejectSite); return p.forget(); } @@ -517,7 +517,7 @@ protected: typename detail::MethodTrait::ReturnType>::Type InvokeMethod(ThisType* aThisVal, MethodType aMethod, ValueType&& aValue) { - return (aThisVal->*aMethod)(Forward(aValue)); + return (aThisVal->*aMethod)(std::forward(aValue)); } template @@ -541,7 +541,7 @@ protected: ValueType&& aValue, CompletionPromiseType&& aCompletionPromise) { - auto p = InvokeMethod(aThisVal, aMethod, Forward(aValue)); + auto p = InvokeMethod(aThisVal, aMethod, std::forward(aValue)); if (aCompletionPromise) { p->ChainTo(aCompletionPromise.forget(), ""); } @@ -562,7 +562,7 @@ protected: MOZ_DIAGNOSTIC_ASSERT( !aCompletionPromise, "Can't do promise chaining for a non-promise-returning method."); - InvokeMethod(aThisVal, aMethod, Forward(aValue)); + InvokeMethod(aThisVal, aMethod, std::forward(aValue)); } template @@ -937,10 +937,10 @@ protected: template auto Then(Ts&&... aArgs) - -> decltype(DeclVal().Then(Forward(aArgs)...)) + -> decltype(DeclVal().Then(std::forward(aArgs)...)) { return static_cast>(*this)->Then( - Forward(aArgs)...); + std::forward(aArgs)...); } void Track(MozPromiseRequestHolder& aRequestHolder) @@ -1115,7 +1115,7 @@ public: PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aResolveSite, this, mCreationSite); return; } - mValue.SetResolve(Forward(aResolveValue)); + mValue.SetResolve(std::forward(aResolveValue)); DispatchAll(); } @@ -1129,7 +1129,7 @@ public: PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aRejectSite, this, mCreationSite); return; } - mValue.SetReject(Forward(aRejectValue)); + mValue.SetReject(std::forward(aRejectValue)); DispatchAll(); } @@ -1143,7 +1143,7 @@ public: PROMISE_LOG("%s ignored already resolved or rejected MozPromise (%p created at %s)", aSite, this, mCreationSite); return; } - mValue = Forward(aValue); + mValue = std::forward(aValue); DispatchAll(); } }; @@ -1357,7 +1357,7 @@ public: MethodCall(MethodType aMethod, ThisType* aThisVal, Args&&... aArgs) : mMethod(aMethod) , mThisVal(aThisVal) - , mArgs(Forward(aArgs)...) + , mArgs(std::forward(aArgs)...) { static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes"); } @@ -1421,7 +1421,7 @@ InvokeAsyncImpl(nsISerialEventTarget* aTarget, ThisType* aThisVal, typedef detail::ProxyRunnable ProxyRunnableType; MethodCallType* methodCall = - new MethodCallType(aMethod, aThisVal, Forward(aArgs)...); + new MethodCallType(aMethod, aThisVal, std::forward(aArgs)...); RefPtr p = new (typename PromiseType::Private)(aCallerName); RefPtr r = new ProxyRunnableType(p, methodCall); aTarget->Dispatch(r.forget()); @@ -1464,7 +1464,7 @@ InvokeAsync(nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCall "Provided Storages and ActualArgTypes should have equal sizes"); return detail::InvokeAsyncImpl( aTarget, aThisVal, aCallerName, aMethod, - Forward(aArgs)...); + std::forward(aArgs)...); } // InvokeAsync with no explicitly-specified storages, will copy arguments and @@ -1484,7 +1484,7 @@ InvokeAsync(nsISerialEventTarget* aTarget, ThisType* aThisVal, const char* aCall "Method's ArgTypes and ActualArgTypes should have equal sizes"); return detail::InvokeAsyncImpl::Type>...>( aTarget, aThisVal, aCallerName, aMethod, - Forward(aArgs)...); + std::forward(aArgs)...); } namespace detail { @@ -1499,7 +1499,7 @@ public: F&& aFunction) : CancelableRunnable("detail::ProxyFunctionRunnable") , mProxyPromise(aProxyPromise) - , mFunction(new FunctionStorage(Forward(aFunction))) + , mFunction(new FunctionStorage(std::forward(aFunction))) { } @@ -1548,7 +1548,7 @@ InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, typedef detail::ProxyFunctionRunnable ProxyRunnableType; auto p = MakeRefPtr(aCallerName); - auto r = MakeRefPtr(p, Forward(aFunction)); + auto r = MakeRefPtr(p, std::forward(aFunction)); aTarget->Dispatch(r.forget()); return p.forget(); } @@ -1568,7 +1568,7 @@ InvokeAsync(nsISerialEventTarget* aTarget, const char* aCallerName, "unplanned copies); Consider move()ing the object."); return detail::InvokeAsync(aTarget, aCallerName, detail::AllowInvokeAsyncFunctionLVRef(), - Forward(aFunction)); + std::forward(aFunction)); } #undef PROMISE_LOG diff --git a/xpcom/threads/nsThreadUtils.h b/xpcom/threads/nsThreadUtils.h index 1b0fc9c17704..43fe2621c2ea 100644 --- a/xpcom/threads/nsThreadUtils.h +++ b/xpcom/threads/nsThreadUtils.h @@ -543,7 +543,7 @@ public: template explicit RunnableFunction(const char* aName, F&& aFunction) : Runnable(aName) - , mFunction(Forward(aFunction)) + , mFunction(std::forward(aFunction)) { } NS_IMETHOD Run() override { @@ -657,7 +657,7 @@ NS_NewRunnableFunction(const char* aName, Function&& aFunction) // to move if possible. return do_AddRef( new mozilla::detail::RunnableFunctionImpl( - aName, mozilla::Forward(aFunction))); + aName, std::forward(aFunction))); } namespace mozilla { @@ -869,7 +869,7 @@ struct StoreCopyPassByValue typedef stored_type passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return m; } }; template @@ -883,7 +883,7 @@ struct StoreCopyPassByConstLRef typedef const stored_type& passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return m; } }; template @@ -897,7 +897,7 @@ struct StoreCopyPassByLRef typedef stored_type& passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return m; } }; template @@ -911,7 +911,7 @@ struct StoreCopyPassByRRef typedef stored_type&& passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return std::move(m); } }; template @@ -953,7 +953,7 @@ struct StoreRefPtrPassByPtr typedef T* passed_type; stored_type m; template - MOZ_IMPLICIT StoreRefPtrPassByPtr(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreRefPtrPassByPtr(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return m.get(); } }; template @@ -995,7 +995,7 @@ struct StoreCopyPassByConstPtr typedef const T* passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return &m; } }; template @@ -1009,7 +1009,7 @@ struct StoreCopyPassByPtr typedef T* passed_type; stored_type m; template - MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward(a)) {} + MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(std::forward(a)) {} passed_type PassAsParameter() { return &m; } }; template @@ -1155,7 +1155,7 @@ struct RunnableMethodArguments final Tuple::Type...> mArguments; template explicit RunnableMethodArguments(As&&... aArguments) - : mArguments(Forward(aArguments)...) + : mArguments(std::forward(aArguments)...) {} template static auto @@ -1201,9 +1201,9 @@ public: explicit RunnableMethodImpl(const char* aName, ForwardedPtrType&& aObj, Method aMethod, Args&&... aArgs) : BaseType(aName) - , mReceiver(Forward(aObj)) + , mReceiver(std::forward(aObj)) , mMethod(aMethod) - , mArgs(Forward(aArgs)...) + , mArgs(std::forward(aArgs)...) { static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes"); } @@ -1413,7 +1413,7 @@ NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) { return do_AddRef( new detail::OwningRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1422,7 +1422,7 @@ NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) { return do_AddRef( new detail::CancelableRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1431,7 +1431,7 @@ NewIdleRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) { return do_AddRef( new detail::IdleRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1442,7 +1442,7 @@ NewIdleRunnableMethodWithTimer(const char* aName, { return do_AddRef( new detail::IdleRunnableMethodWithTimerImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1451,7 +1451,7 @@ NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod) { return do_AddRef( new detail::NonOwningRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1461,7 +1461,7 @@ NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr, { return do_AddRef( new detail::NonOwningCancelableRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1472,7 +1472,7 @@ NewNonOwningIdleRunnableMethod(const char* aName, { return do_AddRef( new detail::NonOwningIdleRunnableMethodImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } template @@ -1483,7 +1483,7 @@ NewNonOwningIdleRunnableMethodWithTimer(const char* aName, { return do_AddRef( new detail::NonOwningIdleRunnableMethodWithTimerImpl( - aName, Forward(aPtr), aMethod)); + aName, std::forward(aPtr), aMethod)); } // Similar to NewRunnableMethod. Call like so: @@ -1498,7 +1498,7 @@ NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod, Args&&... a " size should be equal to number of arguments"); return do_AddRef( new detail::OwningRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } template @@ -1510,7 +1510,7 @@ NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod, " size should be equal to number of arguments"); return do_AddRef( new detail::NonOwningRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } template @@ -1522,7 +1522,7 @@ NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod, " size should be equal to number of arguments"); return do_AddRef( new detail::CancelableRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } template @@ -1534,7 +1534,7 @@ NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr, " size should be equal to number of arguments"); return do_AddRef( new detail::NonOwningCancelableRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } template size should be equal to number of arguments"); return do_AddRef( new detail::IdleRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } template size should be equal to number of arguments"); return do_AddRef( new detail::NonOwningIdleRunnableMethodImpl( - aName, Forward(aPtr), aMethod, mozilla::Forward(aArgs)...)); + aName, std::forward(aPtr), aMethod, std::forward(aArgs)...)); } } // namespace mozilla From d630d8c2689a601929d3abc81f8de843d245066f Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 25 May 2018 21:47:23 +0200 Subject: [PATCH 100/116] Bug 1451973 - Use loadProcessScript instead of loadFrameScript with process message manager. r=mconley. --HG-- extra : rebase_source : d6c059265da06b84278b5d560cd6febf12c24c70 extra : histedit_source : cd38da7e572971fe57a5f581515206cf372dedad --- testing/talos/talos/tests/tabswitch/api.js | 6 +++--- testing/talos/talos/tests/tabswitch/background.js | 4 ++-- testing/talos/talos/tests/tabswitch/schema.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/testing/talos/talos/tests/tabswitch/api.js b/testing/talos/talos/tests/tabswitch/api.js index 183336858c39..753cb98f42e1 100644 --- a/testing/talos/talos/tests/tabswitch/api.js +++ b/testing/talos/talos/tests/tabswitch/api.js @@ -313,13 +313,13 @@ this.tps = class extends ExtensionAPI { getAPI(context) { return { tps: { - setup({ frameScriptPath }) { + setup({ processScriptPath }) { const AboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"] .getService(Ci.nsIAboutNewTabService); AboutNewTabService.newTabURL = "about:blank"; - const frameScriptURL = context.extension.baseURI.resolve(frameScriptPath); - Services.ppmm.loadFrameScript(frameScriptURL, true); + const processScriptURL = context.extension.baseURI.resolve(processScriptPath); + Services.ppmm.loadProcessScript(processScriptURL, true); remotePage = new RemotePages("about:tabswitch"); remotePage.addMessageListener("tabswitch-do-test", function doTest(msg) { test(msg.target.browser.ownerGlobal); diff --git a/testing/talos/talos/tests/tabswitch/background.js b/testing/talos/talos/tests/tabswitch/background.js index 02e45e755763..8a5733709a9b 100644 --- a/testing/talos/talos/tests/tabswitch/background.js +++ b/testing/talos/talos/tests/tabswitch/background.js @@ -8,6 +8,6 @@ * function that is used to report results. */ -let frameScriptPath = "content/tabswitch-content-process.js"; +let processScriptPath = "content/tabswitch-content-process.js"; -browser.tps.setup({ frameScriptPath }); +browser.tps.setup({ processScriptPath }); diff --git a/testing/talos/talos/tests/tabswitch/schema.json b/testing/talos/talos/tests/tabswitch/schema.json index b4cbc2d6b08f..17f16d682ef9 100644 --- a/testing/talos/talos/tests/tabswitch/schema.json +++ b/testing/talos/talos/tests/tabswitch/schema.json @@ -11,9 +11,9 @@ "type": "object", "name": "setupArgs", "properties": { - "frameScriptPath": { + "processScriptPath": { "type": "string", - "description": "Relative path for the frame script to load for the test in the initial tab." + "description": "Relative path for the process script to load for the test in the initial tab." } } }] From 0dbc31467c65b5a9ca514989b762007e5dc9f360 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 16 Apr 2018 15:18:48 +0200 Subject: [PATCH 101/116] Bug 1451973 - Split off process from non-process message managers. r=bz. Process and non-process managers have different script loader interfaces (ProcessScriptLoader/GlobalProcessScriptLoader vs FrameScriptLoader). The WebIDL conversion used the same interface for some process and non-process managers, but because of the different script loader interfaces they really should be using separate interfaces. --HG-- rename : dom/base/ChromeMessageBroadcaster.cpp => dom/base/MessageBroadcaster.cpp rename : dom/base/ChromeMessageBroadcaster.h => dom/base/MessageBroadcaster.h rename : dom/base/ChromeMessageBroadcaster.cpp => dom/base/ParentProcessMessageManager.cpp rename : dom/base/ChromeMessageBroadcaster.h => dom/base/ParentProcessMessageManager.h rename : dom/base/ChromeMessageSender.cpp => dom/base/ProcessMessageManager.cpp rename : dom/base/ChromeMessageSender.h => dom/base/ProcessMessageManager.h extra : rebase_source : c9b0c543f9f367535919a6c6840e5ba038023112 extra : histedit_source : 7749f98e11e25423fcf414cc1f0415104343798a --- dom/base/ChromeMessageBroadcaster.cpp | 46 ---------------- dom/base/ChromeMessageBroadcaster.h | 69 +++++------------------- dom/base/ChromeMessageSender.cpp | 18 ------- dom/base/ChromeMessageSender.h | 28 +++------- dom/base/DocumentOrShadowRoot.h | 2 + dom/base/MessageBroadcaster.cpp | 48 +++++++++++++++++ dom/base/MessageBroadcaster.h | 58 ++++++++++++++++++++ dom/base/MessageListenerManager.cpp | 2 +- dom/base/MessageListenerManager.h | 14 +++-- dom/base/MessageManagerGlobal.h | 2 +- dom/base/MessageSender.h | 8 ++- dom/base/MozQueryInterface.h | 3 +- dom/base/NameSpaceConstants.h | 2 + dom/base/ParentProcessMessageManager.cpp | 38 +++++++++++++ dom/base/ParentProcessMessageManager.h | 55 +++++++++++++++++++ dom/base/ProcessMessageManager.cpp | 41 ++++++++++++++ dom/base/ProcessMessageManager.h | 52 ++++++++++++++++++ dom/base/ShadowRoot.cpp | 1 + dom/base/StyleSheetList.cpp | 1 + dom/base/moz.build | 6 +++ dom/base/nsCCUncollectableMarker.cpp | 9 ++-- dom/base/nsContentUtils.cpp | 7 +-- dom/base/nsContentUtils.h | 4 +- dom/base/nsDOMMutationObserver.cpp | 5 +- dom/base/nsFrameLoader.cpp | 4 +- dom/base/nsFrameLoader.h | 3 +- dom/base/nsFrameMessageManager.cpp | 40 +++++++------- dom/base/nsFrameMessageManager.h | 17 +++--- dom/base/nsIdentifierMapEntry.h | 7 +++ dom/chrome-webidl/MessageManager.webidl | 46 +++++++++++++--- dom/ipc/ContentBridgeParent.cpp | 2 +- dom/ipc/ContentParent.cpp | 7 +-- dom/ipc/nsIContentParent.cpp | 2 +- dom/ipc/nsIContentParent.h | 6 +-- layout/style/nsComputedDOMStyle.h | 1 + 35 files changed, 443 insertions(+), 211 deletions(-) create mode 100644 dom/base/MessageBroadcaster.cpp create mode 100644 dom/base/MessageBroadcaster.h create mode 100644 dom/base/ParentProcessMessageManager.cpp create mode 100644 dom/base/ParentProcessMessageManager.h create mode 100644 dom/base/ProcessMessageManager.cpp create mode 100644 dom/base/ProcessMessageManager.h diff --git a/dom/base/ChromeMessageBroadcaster.cpp b/dom/base/ChromeMessageBroadcaster.cpp index 0d7a3141111b..c37ccbe87976 100644 --- a/dom/base/ChromeMessageBroadcaster.cpp +++ b/dom/base/ChromeMessageBroadcaster.cpp @@ -7,34 +7,11 @@ #include "mozilla/dom/ChromeMessageBroadcaster.h" #include "AccessCheck.h" #include "mozilla/HoldDropJSObjects.h" -#include "mozilla/dom/ContentParent.h" #include "mozilla/dom/MessageManagerBinding.h" namespace mozilla { namespace dom { -ChromeMessageBroadcaster::ChromeMessageBroadcaster(ChromeMessageBroadcaster* aParentManager, - MessageManagerFlags aFlags) - : MessageListenerManager(nullptr, aParentManager, - aFlags | - MessageManagerFlags::MM_BROADCASTER | - MessageManagerFlags::MM_CHROME) -{ - if (mIsProcessManager) { - mozilla::HoldJSObjects(this); - } - if (aParentManager) { - aParentManager->AddChildManager(this); - } -} - -ChromeMessageBroadcaster::~ChromeMessageBroadcaster() -{ - if (mIsProcessManager) { - mozilla::DropJSObjects(this); - } -} - JSObject* ChromeMessageBroadcaster::WrapObject(JSContext* aCx, JS::Handle aGivenProto) @@ -44,28 +21,5 @@ ChromeMessageBroadcaster::WrapObject(JSContext* aCx, return ChromeMessageBroadcasterBinding::Wrap(aCx, this, aGivenProto); } -void -ChromeMessageBroadcaster::ReleaseCachedProcesses() -{ - ContentParent::ReleaseCachedProcesses(); -} - -void -ChromeMessageBroadcaster::AddChildManager(MessageListenerManager* aManager) -{ - mChildManagers.AppendElement(aManager); - - RefPtr kungfuDeathGrip = this; - RefPtr kungfuDeathGrip2 = aManager; - - LoadPendingScripts(this, aManager); -} - -void -ChromeMessageBroadcaster::RemoveChildManager(MessageListenerManager* aManager) -{ - mChildManagers.RemoveElement(aManager); -} - } // namespace dom } // namespace mozilla diff --git a/dom/base/ChromeMessageBroadcaster.h b/dom/base/ChromeMessageBroadcaster.h index 9f7a09460ec7..dcae237eab29 100644 --- a/dom/base/ChromeMessageBroadcaster.h +++ b/dom/base/ChromeMessageBroadcaster.h @@ -7,74 +7,31 @@ #ifndef mozilla_dom_ChromeMessageBroadcaster_h #define mozilla_dom_ChromeMessageBroadcaster_h -#include "mozilla/dom/MessageListenerManager.h" +#include "mozilla/dom/MessageBroadcaster.h" namespace mozilla { namespace dom { -class ChromeMessageBroadcaster final : public MessageListenerManager +/** + * Implementation for the WebIDL ChromeMessageBroadcaster interface. Used for window and + * group message managers. + */ +class ChromeMessageBroadcaster final : public MessageBroadcaster { public: explicit ChromeMessageBroadcaster(MessageManagerFlags aFlags) : ChromeMessageBroadcaster(nullptr, aFlags) { MOZ_ASSERT(!(aFlags & ~(MessageManagerFlags::MM_GLOBAL | - MessageManagerFlags::MM_PROCESSMANAGER | MessageManagerFlags::MM_OWNSCALLBACK))); } - explicit ChromeMessageBroadcaster(ChromeMessageBroadcaster* aParentManager) + explicit ChromeMessageBroadcaster(MessageBroadcaster* aParentManager) : ChromeMessageBroadcaster(aParentManager, MessageManagerFlags::MM_NONE) {} - static ChromeMessageBroadcaster* From(nsFrameMessageManager* aManager) - { - if (aManager->IsBroadcaster() && aManager->IsChrome()) { - return static_cast(aManager); - } - return nullptr; - } - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - void BroadcastAsyncMessage(JSContext* aCx, const nsAString& aMessageName, - JS::Handle aObj, - JS::Handle aObjects, - mozilla::ErrorResult& aError) - { - DispatchAsyncMessage(aCx, aMessageName, aObj, aObjects, nullptr, - JS::UndefinedHandleValue, aError); - } - uint32_t ChildCount() - { - return mChildManagers.Length(); - } - MessageListenerManager* GetChildAt(uint32_t aIndex) - { - return mChildManagers.SafeElementAt(aIndex); - } - void ReleaseCachedProcesses(); - - // ProcessScriptLoader - void LoadProcessScript(const nsAString& aUrl, bool aAllowDelayedLoad, - mozilla::ErrorResult& aError) - { - LoadScript(aUrl, aAllowDelayedLoad, false, aError); - } - void RemoveDelayedProcessScript(const nsAString& aURL) - { - RemoveDelayedScript(aURL); - } - void GetDelayedProcessScripts(JSContext* aCx, - nsTArray>& aScripts, - mozilla::ErrorResult& aError) - { - GetDelayedScripts(aCx, aScripts, aError); - } - - // GlobalProcessScriptLoader - using nsFrameMessageManager::GetInitialProcessData; - // FrameScriptLoader void LoadFrameScript(const nsAString& aUrl, bool aAllowDelayedLoad, bool aRunInGlobalScope, mozilla::ErrorResult& aError) @@ -92,13 +49,13 @@ public: GetDelayedScripts(aCx, aScripts, aError); } - void AddChildManager(MessageListenerManager* aManager); - void RemoveChildManager(MessageListenerManager* aManager); - private: - ChromeMessageBroadcaster(ChromeMessageBroadcaster* aParentManager, - MessageManagerFlags aFlags); - virtual ~ChromeMessageBroadcaster(); + ChromeMessageBroadcaster(MessageBroadcaster* aParentManager, + MessageManagerFlags aFlags) + : MessageBroadcaster(aParentManager, + aFlags | + MessageManagerFlags::MM_CHROME) + {} }; } // namespace dom diff --git a/dom/base/ChromeMessageSender.cpp b/dom/base/ChromeMessageSender.cpp index 6505015e97b8..be17fb437ba4 100644 --- a/dom/base/ChromeMessageSender.cpp +++ b/dom/base/ChromeMessageSender.cpp @@ -10,24 +10,6 @@ namespace mozilla { namespace dom { -ChromeMessageSender::ChromeMessageSender(ipc::MessageManagerCallback* aCallback, - ChromeMessageBroadcaster* aParentManager, - MessageManagerFlags aFlags) - : MessageSender(aCallback, aParentManager, aFlags | MessageManagerFlags::MM_CHROME) -{ - MOZ_ASSERT(!(aFlags & ~(MessageManagerFlags::MM_GLOBAL | - MessageManagerFlags::MM_PROCESSMANAGER | - MessageManagerFlags::MM_OWNSCALLBACK))); - - // This is a bit hackish. We attach to the parent, but only if we have a callback. We - // don't have a callback for the frame message manager, and for parent process message - // managers (except the parent in-process message manager). In those cases we wait until - // the child process is running (see MessageSender::InitWithCallback). - if (aParentManager && mCallback) { - aParentManager->AddChildManager(this); - } -} - JSObject* ChromeMessageSender::WrapObject(JSContext* aCx, JS::Handle aGivenProto) diff --git a/dom/base/ChromeMessageSender.h b/dom/base/ChromeMessageSender.h index 25f85e0b2ecd..152022775e3f 100644 --- a/dom/base/ChromeMessageSender.h +++ b/dom/base/ChromeMessageSender.h @@ -12,35 +12,21 @@ namespace mozilla { namespace dom { -class ChromeMessageBroadcaster; +class MessageBroadcaster; class ChromeMessageSender final : public MessageSender { public: - ChromeMessageSender(ipc::MessageManagerCallback* aCallback, - ChromeMessageBroadcaster* aParentManager, - MessageManagerFlags aFlags=MessageManagerFlags::MM_NONE); + explicit ChromeMessageSender(MessageBroadcaster* aParentManager) + : MessageSender(nullptr, aParentManager, MessageManagerFlags::MM_CHROME) + { + // This is a bit hackish, we wait until the child process is running before attaching + // to the parent manager (see MessageSender::InitWithCallback). + } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - // ProcessScriptLoader - void LoadProcessScript(const nsAString& aUrl, bool aAllowDelayedLoad, - mozilla::ErrorResult& aError) - { - LoadScript(aUrl, aAllowDelayedLoad, false, aError); - } - void RemoveDelayedProcessScript(const nsAString& aURL) - { - RemoveDelayedScript(aURL); - } - void GetDelayedProcessScripts(JSContext* aCx, - nsTArray>& aScripts, - mozilla::ErrorResult& aError) - { - GetDelayedScripts(aCx, aScripts, aError); - } - // FrameScriptLoader void LoadFrameScript(const nsAString& aUrl, bool aAllowDelayedLoad, bool aRunInGlobalScope, mozilla::ErrorResult& aError) diff --git a/dom/base/DocumentOrShadowRoot.h b/dom/base/DocumentOrShadowRoot.h index 6c03e4a0c899..f32f8095deb5 100644 --- a/dom/base/DocumentOrShadowRoot.h +++ b/dom/base/DocumentOrShadowRoot.h @@ -13,6 +13,7 @@ #include "nsIdentifierMapEntry.h" class nsContentList; +class nsIDocument; class nsINode; namespace mozilla { @@ -20,6 +21,7 @@ class StyleSheet; namespace dom { +class Element; class StyleSheetList; class ShadowRoot; diff --git a/dom/base/MessageBroadcaster.cpp b/dom/base/MessageBroadcaster.cpp new file mode 100644 index 000000000000..9f06a813a829 --- /dev/null +++ b/dom/base/MessageBroadcaster.cpp @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "mozilla/dom/MessageBroadcaster.h" +#include "mozilla/dom/ContentParent.h" + +namespace mozilla { +namespace dom { + +MessageBroadcaster::MessageBroadcaster(MessageBroadcaster* aParentManager, + MessageManagerFlags aFlags) + : MessageListenerManager(nullptr, aParentManager, + aFlags | + MessageManagerFlags::MM_BROADCASTER) +{ + if (aParentManager) { + aParentManager->AddChildManager(this); + } +} + +void +MessageBroadcaster::ReleaseCachedProcesses() +{ + ContentParent::ReleaseCachedProcesses(); +} + +void +MessageBroadcaster::AddChildManager(MessageListenerManager* aManager) +{ + mChildManagers.AppendElement(aManager); + + RefPtr kungfuDeathGrip = this; + RefPtr kungfuDeathGrip2 = aManager; + + LoadPendingScripts(this, aManager); +} + +void +MessageBroadcaster::RemoveChildManager(MessageListenerManager* aManager) +{ + mChildManagers.RemoveElement(aManager); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/MessageBroadcaster.h b/dom/base/MessageBroadcaster.h new file mode 100644 index 000000000000..739e43ec76fa --- /dev/null +++ b/dom/base/MessageBroadcaster.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef mozilla_dom_MessageBroadcaster_h +#define mozilla_dom_MessageBroadcaster_h + +#include "mozilla/dom/MessageListenerManager.h" + +namespace mozilla { +namespace dom { + +/** + * Implementation for the WebIDL MessageBroadcaster interface. Base class for window and + * process broadcaster message managers. + */ +class MessageBroadcaster : public MessageListenerManager +{ +public: + static MessageBroadcaster* From(MessageListenerManager* aManager) + { + if (aManager->IsBroadcaster()) { + return static_cast(aManager); + } + return nullptr; + } + + void BroadcastAsyncMessage(JSContext* aCx, const nsAString& aMessageName, + JS::Handle aObj, + JS::Handle aObjects, + mozilla::ErrorResult& aError) + { + DispatchAsyncMessage(aCx, aMessageName, aObj, aObjects, nullptr, + JS::UndefinedHandleValue, aError); + } + uint32_t ChildCount() + { + return mChildManagers.Length(); + } + MessageListenerManager* GetChildAt(uint32_t aIndex) + { + return mChildManagers.SafeElementAt(aIndex); + } + void ReleaseCachedProcesses(); + + void AddChildManager(MessageListenerManager* aManager); + void RemoveChildManager(MessageListenerManager* aManager); + +protected: + MessageBroadcaster(MessageBroadcaster* aParentManager, MessageManagerFlags aFlags); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_MessageBroadcaster_h diff --git a/dom/base/MessageListenerManager.cpp b/dom/base/MessageListenerManager.cpp index 3ddf444da36a..c21c7d12175c 100644 --- a/dom/base/MessageListenerManager.cpp +++ b/dom/base/MessageListenerManager.cpp @@ -10,7 +10,7 @@ namespace mozilla { namespace dom { MessageListenerManager::MessageListenerManager(ipc::MessageManagerCallback* aCallback, - ChromeMessageBroadcaster* aParentManager, + MessageBroadcaster* aParentManager, ipc::MessageManagerFlags aFlags) : nsFrameMessageManager(aCallback, aFlags), mParentManager(aParentManager) diff --git a/dom/base/MessageListenerManager.h b/dom/base/MessageListenerManager.h index 8a6442e16649..2b38486d25fd 100644 --- a/dom/base/MessageListenerManager.h +++ b/dom/base/MessageListenerManager.h @@ -14,6 +14,12 @@ namespace mozilla { namespace dom { +class MessageBroadcaster; + +/** + * Implementation for the WebIDL MessageListenerManager interface. Base class for message + * managers that are exposed to script. + */ class MessageListenerManager : public nsFrameMessageManager, public nsWrapperCache { @@ -22,12 +28,12 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MessageListenerManager, nsFrameMessageManager) - ChromeMessageBroadcaster* GetParentObject() + MessageBroadcaster* GetParentObject() { return mParentManager; } - virtual ChromeMessageBroadcaster* GetParentManager() override + virtual MessageBroadcaster* GetParentManager() override { return mParentManager; } @@ -40,11 +46,11 @@ public: protected: MessageListenerManager(ipc::MessageManagerCallback* aCallback, - ChromeMessageBroadcaster* aParentManager, + MessageBroadcaster* aParentManager, MessageManagerFlags aFlags); virtual ~MessageListenerManager(); - RefPtr mParentManager; + RefPtr mParentManager; }; } // namespace dom diff --git a/dom/base/MessageManagerGlobal.h b/dom/base/MessageManagerGlobal.h index 03c8446725d7..55d64c469eda 100644 --- a/dom/base/MessageManagerGlobal.h +++ b/dom/base/MessageManagerGlobal.h @@ -78,7 +78,7 @@ public: mMessageManager->SendAsyncMessage(aCx, aMessageName, aObj, aObjects, aPrincipal, aTransfers, aError); } - already_AddRefed GetProcessMessageManager(mozilla::ErrorResult& aError) + already_AddRefed GetProcessMessageManager(mozilla::ErrorResult& aError) { if (!mMessageManager) { aError.Throw(NS_ERROR_NULL_POINTER); diff --git a/dom/base/MessageSender.h b/dom/base/MessageSender.h index 96d7a74ecb3c..54bc1e3f1a23 100644 --- a/dom/base/MessageSender.h +++ b/dom/base/MessageSender.h @@ -12,6 +12,12 @@ namespace mozilla { namespace dom { +class MessageBroadcaster; + +/** + * Implementation for the WebIDL MessageSender interface. Base class for frame and child + * process message managers. + */ class MessageSender : public MessageListenerManager { public: @@ -19,7 +25,7 @@ public: protected: MessageSender(ipc::MessageManagerCallback* aCallback, - ChromeMessageBroadcaster* aParentManager, + MessageBroadcaster* aParentManager, MessageManagerFlags aFlags) : MessageListenerManager(aCallback, aParentManager, aFlags) {} diff --git a/dom/base/MozQueryInterface.h b/dom/base/MozQueryInterface.h index f67643b79ea0..5adcfcba413c 100644 --- a/dom/base/MozQueryInterface.h +++ b/dom/base/MozQueryInterface.h @@ -20,8 +20,9 @@ */ #include "mozilla/dom/BindingDeclarations.h" -#include "mozilla/dom/ChromeUtilsBinding.h" +#include "mozilla/dom/NonRefcountedDOMObject.h" #include "mozilla/ErrorResult.h" +#include "nsID.h" namespace mozilla { namespace dom { diff --git a/dom/base/NameSpaceConstants.h b/dom/base/NameSpaceConstants.h index 1ef1b1046b11..13371c9f33fa 100644 --- a/dom/base/NameSpaceConstants.h +++ b/dom/base/NameSpaceConstants.h @@ -7,6 +7,8 @@ #ifndef mozilla_dom_NameSpaceConstants_h__ #define mozilla_dom_NameSpaceConstants_h__ +#include + #define kNameSpaceID_Unknown -1 // 0 is special at C++, so use a static const int32_t for // kNameSpaceID_None to keep if from being cast to pointers diff --git a/dom/base/ParentProcessMessageManager.cpp b/dom/base/ParentProcessMessageManager.cpp new file mode 100644 index 000000000000..5dc7e565016a --- /dev/null +++ b/dom/base/ParentProcessMessageManager.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "mozilla/dom/ParentProcessMessageManager.h" +#include "AccessCheck.h" +#include "mozilla/HoldDropJSObjects.h" +#include "mozilla/dom/MessageManagerBinding.h" + +namespace mozilla { +namespace dom { + +ParentProcessMessageManager::ParentProcessMessageManager() + : MessageBroadcaster(nullptr, + MessageManagerFlags::MM_CHROME | + MessageManagerFlags::MM_PROCESSMANAGER) +{ + mozilla::HoldJSObjects(this); +} + +ParentProcessMessageManager::~ParentProcessMessageManager() +{ + mozilla::DropJSObjects(this); +} + +JSObject* +ParentProcessMessageManager::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) +{ + MOZ_ASSERT(nsContentUtils::IsSystemCaller(aCx)); + + return ParentProcessMessageManagerBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/ParentProcessMessageManager.h b/dom/base/ParentProcessMessageManager.h new file mode 100644 index 000000000000..e2bc4fecbbf7 --- /dev/null +++ b/dom/base/ParentProcessMessageManager.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef mozilla_dom_ParentProcessMessageManager_h +#define mozilla_dom_ParentProcessMessageManager_h + +#include "mozilla/dom/MessageBroadcaster.h" + +namespace mozilla { +namespace dom { + +/** + * Implementation for the WebIDL ParentProcessMessageManager interface. + * ParentProcessMessageManager is used in a parent process to communicate with all the + * child processes. + */ +class ParentProcessMessageManager final : public MessageBroadcaster +{ +public: + ParentProcessMessageManager(); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + // ProcessScriptLoader + void LoadProcessScript(const nsAString& aUrl, bool aAllowDelayedLoad, + mozilla::ErrorResult& aError) + { + LoadScript(aUrl, aAllowDelayedLoad, false, aError); + } + void RemoveDelayedProcessScript(const nsAString& aURL) + { + RemoveDelayedScript(aURL); + } + void GetDelayedProcessScripts(JSContext* aCx, + nsTArray>& aScripts, + mozilla::ErrorResult& aError) + { + GetDelayedScripts(aCx, aScripts, aError); + } + + // GlobalProcessScriptLoader + using nsFrameMessageManager::GetInitialProcessData; + +private: + virtual ~ParentProcessMessageManager(); +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_ParentProcessMessageManager_h diff --git a/dom/base/ProcessMessageManager.cpp b/dom/base/ProcessMessageManager.cpp new file mode 100644 index 000000000000..7024307bb825 --- /dev/null +++ b/dom/base/ProcessMessageManager.cpp @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "mozilla/dom/ProcessMessageManager.h" +#include "mozilla/dom/MessageManagerBinding.h" + +namespace mozilla { +namespace dom { + +ProcessMessageManager::ProcessMessageManager(ipc::MessageManagerCallback* aCallback, + ParentProcessMessageManager* aParentManager, + MessageManagerFlags aFlags) + : MessageSender(aCallback, aParentManager, + aFlags | MessageManagerFlags::MM_CHROME | + MessageManagerFlags::MM_PROCESSMANAGER) +{ + MOZ_ASSERT(!(aFlags & ~(MessageManagerFlags::MM_GLOBAL | + MessageManagerFlags::MM_OWNSCALLBACK))); + + // This is a bit hackish. We attach to the parent manager, but only if we have a + // callback (which is only for the in-process message manager). For other cases we wait + // until the child process is running (see MessageSender::InitWithCallback). + if (aParentManager && mCallback) { + aParentManager->AddChildManager(this); + } +} + +JSObject* +ProcessMessageManager::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) +{ + MOZ_ASSERT(nsContentUtils::IsSystemCaller(aCx)); + + return ProcessMessageManagerBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/ProcessMessageManager.h b/dom/base/ProcessMessageManager.h new file mode 100644 index 000000000000..0142869e62dc --- /dev/null +++ b/dom/base/ProcessMessageManager.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef mozilla_dom_ProcessMessageManager_h +#define mozilla_dom_ProcessMessageManager_h + +#include "mozilla/dom/MessageSender.h" + +namespace mozilla { +namespace dom { + +class ParentProcessMessageManager; + +/** + * ProcessMessageManager is used in a parent process to communicate with a child process + * (or with the process itself in a single-process scenario). + */ +class ProcessMessageManager final : public MessageSender +{ +public: + ProcessMessageManager(ipc::MessageManagerCallback* aCallback, + ParentProcessMessageManager* aParentManager, + MessageManagerFlags aFlags=MessageManagerFlags::MM_NONE); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + // ProcessScriptLoader + void LoadProcessScript(const nsAString& aUrl, bool aAllowDelayedLoad, + mozilla::ErrorResult& aError) + { + LoadScript(aUrl, aAllowDelayedLoad, false, aError); + } + void RemoveDelayedProcessScript(const nsAString& aURL) + { + RemoveDelayedScript(aURL); + } + void GetDelayedProcessScripts(JSContext* aCx, + nsTArray>& aScripts, + mozilla::ErrorResult& aError) + { + GetDelayedScripts(aCx, aScripts, aError); + } +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_ProcessMessageManager_h diff --git a/dom/base/ShadowRoot.cpp b/dom/base/ShadowRoot.cpp index 3e230c3fdfd1..39fdf953d489 100644 --- a/dom/base/ShadowRoot.cpp +++ b/dom/base/ShadowRoot.cpp @@ -18,6 +18,7 @@ #include "mozilla/ServoStyleRuleMap.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" +#include "mozilla/dom/StyleSheetList.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/dom/base/StyleSheetList.cpp b/dom/base/StyleSheetList.cpp index ada052bcc287..7d5c28d6ac63 100644 --- a/dom/base/StyleSheetList.cpp +++ b/dom/base/StyleSheetList.cpp @@ -7,6 +7,7 @@ #include "mozilla/dom/StyleSheetList.h" #include "mozilla/dom/StyleSheetListBinding.h" +#include "nsINode.h" namespace mozilla { namespace dom { diff --git a/dom/base/moz.build b/dom/base/moz.build index 6754919719a1..afa4d28a4be4 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -190,6 +190,7 @@ EXPORTS.mozilla.dom += [ 'IntlUtils.h', 'Link.h', 'Location.h', + 'MessageBroadcaster.h', 'MessageListenerManager.h', 'MessageManagerGlobal.h', 'MessageSender.h', @@ -199,8 +200,10 @@ EXPORTS.mozilla.dom += [ 'NodeInfo.h', 'NodeInfoInlines.h', 'NodeIterator.h', + 'ParentProcessMessageManager.h', 'Pose.h', 'ProcessGlobal.h', + 'ProcessMessageManager.h', 'ResponsiveImageSelector.h', 'SameProcessMessageQueue.h', 'ScreenOrientation.h', @@ -271,6 +274,7 @@ UNIFIED_SOURCES += [ 'IntlUtils.cpp', 'Link.cpp', 'Location.cpp', + 'MessageBroadcaster.cpp', 'MessageListenerManager.cpp', 'MessageManagerGlobal.cpp', 'MessageSender.cpp', @@ -344,9 +348,11 @@ UNIFIED_SOURCES += [ 'nsXHTMLContentSerializer.cpp', 'nsXMLContentSerializer.cpp', 'nsXMLNameSpaceMap.cpp', + 'ParentProcessMessageManager.cpp', 'Pose.cpp', 'PostMessageEvent.cpp', 'ProcessGlobal.cpp', + 'ProcessMessageManager.cpp', 'ResponsiveImageSelector.cpp', 'SameProcessMessageQueue.cpp', 'ScreenOrientation.cpp', diff --git a/dom/base/nsCCUncollectableMarker.cpp b/dom/base/nsCCUncollectableMarker.cpp index 25eb7189eb99..0c93a584300c 100644 --- a/dom/base/nsCCUncollectableMarker.cpp +++ b/dom/base/nsCCUncollectableMarker.cpp @@ -30,7 +30,9 @@ #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/EventListenerManager.h" +#include "mozilla/dom/ChromeMessageBroadcaster.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/ParentProcessMessageManager.h" #include "mozilla/dom/ProcessGlobal.h" #include "mozilla/dom/TabChild.h" #include "mozilla/dom/TimeoutManager.h" @@ -86,7 +88,7 @@ nsCCUncollectableMarker::Init() } static void -MarkChildMessageManagers(ChromeMessageBroadcaster* aMM) +MarkChildMessageManagers(MessageBroadcaster* aMM) { aMM->MarkForCC(); @@ -97,9 +99,8 @@ MarkChildMessageManagers(ChromeMessageBroadcaster* aMM) continue; } - RefPtr strongNonLeafMM = - ChromeMessageBroadcaster::From(childMM); - ChromeMessageBroadcaster* nonLeafMM = strongNonLeafMM; + RefPtr strongNonLeafMM = MessageBroadcaster::From(childMM); + MessageBroadcaster* nonLeafMM = strongNonLeafMM; MessageListenerManager* tabMM = childMM; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 09fa42aecf79..1ffc7355c230 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -39,6 +39,7 @@ #include "mozilla/LoadInfo.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/CustomElementRegistry.h" +#include "mozilla/dom/MessageBroadcaster.h" #include "mozilla/dom/DocumentFragment.h" #include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMExceptionBinding.h" @@ -7656,7 +7657,7 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost) } bool -nsContentUtils::CallOnAllRemoteChildren(ChromeMessageBroadcaster* aManager, +nsContentUtils::CallOnAllRemoteChildren(MessageBroadcaster* aManager, CallOnRemoteChildFunction aCallback, void* aArg) { @@ -7667,7 +7668,7 @@ nsContentUtils::CallOnAllRemoteChildren(ChromeMessageBroadcaster* aManager, continue; } - RefPtr nonLeafMM = ChromeMessageBroadcaster::From(childMM); + RefPtr nonLeafMM = MessageBroadcaster::From(childMM); if (nonLeafMM) { if (CallOnAllRemoteChildren(nonLeafMM, aCallback, aArg)) { return true; @@ -7697,7 +7698,7 @@ nsContentUtils::CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow, { nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(aWindow); if (window->IsChromeWindow()) { - RefPtr windowMM = window->GetMessageManager(); + RefPtr windowMM = window->GetMessageManager(); if (windowMM) { CallOnAllRemoteChildren(windowMM, aCallback, aArg); } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 5972794b22ab..da44e0b22185 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -124,7 +124,6 @@ class EventListenerManager; class HTMLEditor; namespace dom { -class ChromeMessageBroadcaster; struct CustomElementDefinition; class DocumentFragment; class Element; @@ -135,6 +134,7 @@ class IPCDataTransfer; class IPCDataTransferItem; struct LifecycleCallbackArgs; struct LifecycleAdoptedCallbackArgs; +class MessageBroadcaster; class NodeInfo; class nsIContentChild; class nsIContentParent; @@ -3305,7 +3305,7 @@ private: mozilla::dom::AutocompleteInfo& aInfo, bool aGrantAllValidValue = false); - static bool CallOnAllRemoteChildren(mozilla::dom::ChromeMessageBroadcaster* aManager, + static bool CallOnAllRemoteChildren(mozilla::dom::MessageBroadcaster* aManager, CallOnRemoteChildFunction aCallback, void* aArg); diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index bb0944704f8c..fe3589bfba4a 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -23,10 +23,7 @@ #include "nsThreadUtils.h" using namespace mozilla; - -using mozilla::dom::TreeOrderComparator; -using mozilla::dom::Animation; -using mozilla::dom::Element; +using namespace mozilla::dom; AutoTArray, 4>* nsDOMMutationObserver::sScheduledMutationObservers = nullptr; diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 1256e548e36e..01b87d973a0d 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -2947,7 +2947,7 @@ nsFrameLoader::EnsureMessageManager() parentManager = nsFrameMessageManager::GetGlobalMessageManager(); } - mMessageManager = new ChromeMessageSender(nullptr, parentManager); + mMessageManager = new ChromeMessageSender(parentManager); if (!IsRemoteFrame()) { nsresult rv = MaybeCreateDocShell(); if (NS_FAILED(rv)) { @@ -3388,7 +3388,7 @@ nsFrameLoader::PopulateUserContextIdFromAttribute(OriginAttributes& aAttr) return NS_OK; } -ChromeMessageSender* +ProcessMessageManager* nsFrameLoader::GetProcessMessageManager() const { return mRemoteBrowser ? mRemoteBrowser->Manager()->GetMessageManager() diff --git a/dom/base/nsFrameLoader.h b/dom/base/nsFrameLoader.h index b1dd8375454b..a26c89740756 100644 --- a/dom/base/nsFrameLoader.h +++ b/dom/base/nsFrameLoader.h @@ -53,6 +53,7 @@ class ChromeMessageSender; class ContentParent; class MessageSender; class PBrowserParent; +class ProcessMessageManager; class Promise; class TabParent; class MutableTabContext; @@ -333,7 +334,7 @@ public: // Properly retrieves documentSize of any subdocument type. nsresult GetWindowDimensions(nsIntRect& aRect); - virtual mozilla::dom::ChromeMessageSender* GetProcessMessageManager() const override; + virtual mozilla::dom::ProcessMessageManager* GetProcessMessageManager() const override; // public because a callback needs these. RefPtr mMessageManager; diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 1efabc2625cc..bc8a3a960b7a 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -36,13 +36,14 @@ #include "mozilla/Telemetry.h" #include "mozilla/dom/ChildProcessMessageManager.h" #include "mozilla/dom/ChromeMessageBroadcaster.h" -#include "mozilla/dom/ChromeMessageSender.h" #include "mozilla/dom/File.h" #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/MessagePort.h" #include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/ParentProcessMessageManager.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessGlobal.h" +#include "mozilla/dom/ProcessMessageManager.h" #include "mozilla/dom/ResolveSystemBinding.h" #include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/ScriptSettings.h" @@ -162,7 +163,7 @@ MessageManagerCallback::DoGetRemoteType(nsAString& aRemoteType, ErrorResult& aError) const { aRemoteType.Truncate(); - mozilla::dom::ChromeMessageSender* parent = GetProcessMessageManager(); + mozilla::dom::ProcessMessageManager* parent = GetProcessMessageManager(); if (!parent) { return; } @@ -916,8 +917,7 @@ nsFrameMessageManager::Close() if (!mClosed) { nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { - obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this), - "message-manager-close", nullptr); + obs->NotifyObservers(this, "message-manager-close", nullptr); } } mClosed = true; @@ -934,8 +934,7 @@ nsFrameMessageManager::Disconnect(bool aRemoveFromParent) if (!mDisconnected) { nsCOMPtr obs = mozilla::services::GetObserverService(); if (obs) { - obs->NotifyObservers(NS_ISUPPORTS_CAST(nsIContentFrameMessageManager*, this), - "message-manager-disconnect", nullptr); + obs->NotifyObservers(this, "message-manager-disconnect", nullptr); } } @@ -1000,10 +999,10 @@ nsFrameMessageManager::GetInitialProcessData(JSContext* aCx, aInitialProcessData.set(init); } -already_AddRefed +already_AddRefed nsFrameMessageManager::GetProcessMessageManager(ErrorResult& aError) { - RefPtr pmm; + RefPtr pmm; if (mCallback) { pmm = mCallback->GetProcessMessageManager(); } @@ -1442,7 +1441,7 @@ nsMessageManagerScriptExecutor::MarkScopesForCC() NS_IMPL_ISUPPORTS(nsScriptCacheCleaner, nsIObserver) ChildProcessMessageManager* nsFrameMessageManager::sChildProcessManager = nullptr; -ChromeMessageBroadcaster* nsFrameMessageManager::sParentProcessManager = nullptr; +ParentProcessMessageManager* nsFrameMessageManager::sParentProcessManager = nullptr; nsFrameMessageManager* nsFrameMessageManager::sSameProcessParentManager = nullptr; class nsAsyncMessageToSameProcessChild : public nsSameProcessAsyncMessageBase, @@ -1457,7 +1456,7 @@ public: NS_IMETHOD Run() override { nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager(); - ReceiveMessage(static_cast(ppm), nullptr, ppm); + ReceiveMessage(ppm, nullptr, ppm); return NS_OK; } }; @@ -1594,7 +1593,7 @@ public: nsresult HandleMessage() override { nsFrameMessageManager* ppm = nsFrameMessageManager::sSameProcessParentManager; - ReceiveMessage(static_cast(ppm), nullptr, ppm); + ReceiveMessage(ppm, nullptr, ppm); return NS_OK; } }; @@ -1662,8 +1661,7 @@ NS_NewParentProcessMessageManager(nsISupports** aResult) { NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager, "Re-creating sParentProcessManager"); - RefPtr mm = - new ChromeMessageBroadcaster(MessageManagerFlags::MM_PROCESSMANAGER); + RefPtr mm = new ParentProcessMessageManager(); nsFrameMessageManager::sParentProcessManager = mm; nsFrameMessageManager::NewProcessMessageManager(false); // Create same process message manager. mm.forget(aResult); @@ -1671,7 +1669,7 @@ NS_NewParentProcessMessageManager(nsISupports** aResult) } -ChromeMessageSender* +ProcessMessageManager* nsFrameMessageManager::NewProcessMessageManager(bool aIsRemote) { if (!nsFrameMessageManager::sParentProcessManager) { @@ -1681,18 +1679,16 @@ nsFrameMessageManager::NewProcessMessageManager(bool aIsRemote) MOZ_ASSERT(nsFrameMessageManager::sParentProcessManager, "parent process manager not created"); - ChromeMessageSender* mm; + ProcessMessageManager* mm; if (aIsRemote) { // Callback is set in ContentParent::InitInternal so that the process has // already started when we send pending scripts. - mm = new ChromeMessageSender(nullptr, - nsFrameMessageManager::sParentProcessManager, - MessageManagerFlags::MM_PROCESSMANAGER); + mm = new ProcessMessageManager(nullptr, + nsFrameMessageManager::sParentProcessManager); } else { - mm = new ChromeMessageSender(new SameParentProcessMessageManagerCallback(), - nsFrameMessageManager::sParentProcessManager, - MessageManagerFlags::MM_PROCESSMANAGER | - MessageManagerFlags::MM_OWNSCALLBACK); + mm = new ProcessMessageManager(new SameParentProcessMessageManagerCallback(), + nsFrameMessageManager::sParentProcessManager, + MessageManagerFlags::MM_OWNSCALLBACK); sSameProcessParentManager = mm; } return mm; diff --git a/dom/base/nsFrameMessageManager.h b/dom/base/nsFrameMessageManager.h index 8c11f63606d4..fe886ba1c058 100644 --- a/dom/base/nsFrameMessageManager.h +++ b/dom/base/nsFrameMessageManager.h @@ -43,12 +43,14 @@ class nsIContentParent; class nsIContentChild; class ChildProcessMessageManager; class ChromeMessageBroadcaster; -class ChromeMessageSender; class ClonedMessageData; +class MessageBroadcaster; class MessageListener; class MessageListenerManager; class MessageManagerReporter; template class Optional; +class ParentProcessMessageManager; +class ProcessMessageManager; namespace ipc { @@ -96,7 +98,7 @@ public: return NS_OK; } - virtual mozilla::dom::ChromeMessageSender* GetProcessMessageManager() const + virtual mozilla::dom::ProcessMessageManager* GetProcessMessageManager() const { return nullptr; } @@ -202,7 +204,7 @@ public: DispatchAsyncMessage(aCx, aMessageName, aObj, aObjects, aPrincipal, aTransfers, aError); } - already_AddRefed + already_AddRefed GetProcessMessageManager(mozilla::ErrorResult& aError); void GetRemoteType(nsAString& aRemoteType, mozilla::ErrorResult& aError) const; @@ -234,8 +236,7 @@ public: NS_DECL_NSIMESSAGESENDER NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER - static mozilla::dom::ChromeMessageSender* - NewProcessMessageManager(bool aIsRemote); + static mozilla::dom::ProcessMessageManager* NewProcessMessageManager(bool aIsRemote); void ReceiveMessage(nsISupports* aTarget, nsFrameLoader* aTargetFrameLoader, const nsAString& aMessage, bool aIsSync, @@ -269,7 +270,7 @@ public: // GetGlobalMessageManager creates the global message manager if it hasn't been yet. static already_AddRefed GetGlobalMessageManager(); - static mozilla::dom::ChromeMessageBroadcaster* GetParentProcessManager() + static mozilla::dom::ParentProcessMessageManager* GetParentProcessManager() { return sParentProcessManager; } @@ -289,7 +290,7 @@ public: protected: friend class MMListenerRemover; - virtual mozilla::dom::ChromeMessageBroadcaster* GetParentManager() + virtual mozilla::dom::MessageBroadcaster* GetParentManager() { return nullptr; } @@ -343,7 +344,7 @@ protected: void LoadPendingScripts(nsFrameMessageManager* aManager, nsFrameMessageManager* aChildMM); public: - static mozilla::dom::ChromeMessageBroadcaster* sParentProcessManager; + static mozilla::dom::ParentProcessMessageManager* sParentProcessManager; static nsFrameMessageManager* sSameProcessParentManager; static nsTArray >* sPendingSameProcessAsyncMessages; private: diff --git a/dom/base/nsIdentifierMapEntry.h b/dom/base/nsIdentifierMapEntry.h index be6dbc2a3e3f..64a12525d2ad 100644 --- a/dom/base/nsIdentifierMapEntry.h +++ b/dom/base/nsIdentifierMapEntry.h @@ -19,6 +19,7 @@ #include "nsCOMPtr.h" #include "nsAtom.h" +#include "nsHashKeys.h" #include "nsTArray.h" #include "nsTHashtable.h" @@ -26,6 +27,12 @@ class nsIContent; class nsContentList; class nsBaseContentList; +namespace mozilla { +namespace dom { +class Element; +} +} + /** * Right now our identifier map entries contain information for 'name' * and 'id' mappings of a given string. This is so that diff --git a/dom/chrome-webidl/MessageManager.webidl b/dom/chrome-webidl/MessageManager.webidl index 2883091d8efb..1ecc0651e247 100644 --- a/dom/chrome-webidl/MessageManager.webidl +++ b/dom/chrome-webidl/MessageManager.webidl @@ -19,7 +19,7 @@ interface Principal; * * Message managers that always have exactly one "other side" are of * type MessageSender. Parent-side message managers that have many - * "other sides" are of type ChromeMessageBroadcaster. + * "other sides" are of type MessageBroadcaster. * * Child-side message managers can send synchronous messages to their * parent side, but not the other way around. @@ -94,13 +94,13 @@ interface Principal; * ---------- * * The global MMg and window MMw's are message broadcasters implementing - * ChromeMessageBroadcaster while the frame MMp's are simple message - * senders (MessageSender). Their counterparts in the content processes - * are message senders implementing ContentFrameMessageManager. + * MessageBroadcaster while the frame MMp's are simple message senders (MessageSender). + * Their counterparts in the content processes are message senders implementing + * ContentFrameMessageManager. * * MessageListenerManager * / \ - * MessageSender ChromeMessageBroadcaster + * MessageSender MessageBroadcaster * | * SyncMessageSender (content process/in-process only) * | @@ -352,6 +352,10 @@ interface SyncMessageSender : MessageSender optional Principal? principal = null); }; +/** + * ChildProcessMessageManager is used in a child process to communicate with the parent + * process. + */ [ChromeOnly] interface ChildProcessMessageManager : SyncMessageSender { @@ -503,7 +507,7 @@ ContentProcessMessageManager implements MessageManagerGlobal; * managers within its window. */ [ChromeOnly] -interface ChromeMessageBroadcaster : MessageListenerManager +interface MessageBroadcaster : MessageListenerManager { /** * Like |sendAsyncMessage()|, but also broadcasts this message to @@ -534,12 +538,38 @@ interface ChromeMessageBroadcaster : MessageListenerManager */ void releaseCachedProcesses(); }; -ChromeMessageBroadcaster implements GlobalProcessScriptLoader; + +/** + * ChromeMessageBroadcaster is used for window and group message managers. + */ +[ChromeOnly] +interface ChromeMessageBroadcaster : MessageBroadcaster +{ +}; ChromeMessageBroadcaster implements FrameScriptLoader; +/** + * ParentProcessMessageManager is used in a parent process to communicate with all the + * child processes. + */ +[ChromeOnly] +interface ParentProcessMessageManager : MessageBroadcaster +{ +}; +ParentProcessMessageManager implements GlobalProcessScriptLoader; + [ChromeOnly] interface ChromeMessageSender : MessageSender { }; -ChromeMessageSender implements ProcessScriptLoader; ChromeMessageSender implements FrameScriptLoader; + +/** + * ProcessMessageManager is used in a parent process to communicate with a child process + * (or with the process itself in a single-process scenario). + */ +[ChromeOnly] +interface ProcessMessageManager : MessageSender +{ +}; +ProcessMessageManager implements ProcessScriptLoader; diff --git a/dom/ipc/ContentBridgeParent.cpp b/dom/ipc/ContentBridgeParent.cpp index f0640605406a..5eec3aa13258 100644 --- a/dom/ipc/ContentBridgeParent.cpp +++ b/dom/ipc/ContentBridgeParent.cpp @@ -5,7 +5,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/ContentBridgeParent.h" -#include "mozilla/dom/ChromeMessageSender.h" +#include "mozilla/dom/ProcessMessageManager.h" #include "mozilla/dom/TabParent.h" #include "mozilla/jsipc/CrossProcessObjectWrappers.h" #include "nsXULAppAPI.h" diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index d79f7be3fc1a..a6a8a31b553c 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -157,7 +157,8 @@ #include "nsThread.h" #include "nsWindowWatcher.h" #include "nsIXULRuntime.h" -#include "mozilla/dom/ChromeMessageBroadcaster.h" +#include "mozilla/dom/ParentProcessMessageManager.h" +#include "mozilla/dom/ProcessMessageManager.h" #include "mozilla/dom/nsMixedContentBlocker.h" #include "nsMemoryInfoDumper.h" #include "nsMemoryReporterManager.h" @@ -534,7 +535,7 @@ ScriptableCPInfo::GetMessageManager(nsISupports** aMessenger) return NS_ERROR_NOT_INITIALIZED; } - RefPtr manager = mContentParent->GetMessageManager(); + RefPtr manager = mContentParent->GetMessageManager(); manager.forget(aMessenger); return NS_OK; } @@ -2239,7 +2240,7 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority) if (ssm) { ssm->CloneDomainPolicy(&xpcomInit.domainPolicy()); - if (ChromeMessageBroadcaster* mm = nsFrameMessageManager::sParentProcessManager) { + if (ParentProcessMessageManager* mm = nsFrameMessageManager::sParentProcessManager) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(xpc::PrivilegedJunkScope()))) { MOZ_CRASH(); diff --git a/dom/ipc/nsIContentParent.cpp b/dom/ipc/nsIContentParent.cpp index 2f4ca4b70f90..b269451bd80e 100644 --- a/dom/ipc/nsIContentParent.cpp +++ b/dom/ipc/nsIContentParent.cpp @@ -8,12 +8,12 @@ #include "mozilla/Preferences.h" #include "mozilla/dom/File.h" -#include "mozilla/dom/ChromeMessageSender.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentBridgeParent.h" #include "mozilla/dom/ContentProcessManager.h" #include "mozilla/dom/PTabContext.h" #include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/ProcessMessageManager.h" #include "mozilla/dom/TabParent.h" #include "mozilla/dom/ipc/IPCBlobInputStreamParent.h" #include "mozilla/dom/ipc/StructuredCloneData.h" diff --git a/dom/ipc/nsIContentParent.h b/dom/ipc/nsIContentParent.h index 7bddee9b1321..e0bbd9467db4 100644 --- a/dom/ipc/nsIContentParent.h +++ b/dom/ipc/nsIContentParent.h @@ -44,7 +44,7 @@ namespace dom { class Blob; class BlobConstructorParams; class BlobImpl; -class ChromeMessageSender; +class ProcessMessageManager; class ContentParent; class ContentBridgeParent; class IPCTabContext; @@ -89,7 +89,7 @@ public: ContentBridgeParent* AsContentBridgeParent(); - mozilla::dom::ChromeMessageSender* GetMessageManager() const { return mMessageManager; } + mozilla::dom::ProcessMessageManager* GetMessageManager() const { return mMessageManager; } virtual bool SendActivate(PBrowserParent* aTab) = 0; @@ -162,7 +162,7 @@ protected: // IPDL methods const ClonedMessageData& aData); protected: // members - RefPtr mMessageManager; + RefPtr mMessageManager; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIContentParent, NS_ICONTENTPARENT_IID) diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 4581a7326b4d..ffd7d790be02 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -14,6 +14,7 @@ #include "mozilla/Attributes.h" #include "mozilla/StyleComplexColor.h" #include "mozilla/UniquePtr.h" +#include "mozilla/dom/Element.h" #include "nsCOMPtr.h" #include "nsContentUtils.h" #include "nscore.h" From 4efe1804358ffc4ad93ed499e94860181d618ee3 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 28 May 2018 22:23:45 +0200 Subject: [PATCH 102/116] Bug 1464639 - Call JSPurpleBuffer::Destroy before shutting down the CC. r=mccr8. Currently we call JSPurpleBuffer::Destroy from nsCycleCollector::PrepareForGarbageCollection. If the CC is shut down after a call to nsCycleCollector::GetJSPurpleBuffer (which creates a JSPurpleBuffer) but before a GC happens, we'll release the strong reference in mJSPurpleBuffer from nsCycleCollector's destructor but we won't call JSPurpleBuffer::Destroy. That leaves a stale pointer to the JSPurpleBuffer in the JSHolder's hash. --HG-- extra : rebase_source : b21a0953ae5b3a470dbd22b8285bffb858f87f13 extra : histedit_source : 1959a4480066fc0920830428023ce01e0768c08e --- xpcom/base/nsCycleCollector.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 22f005201c35..5d36dd2956c2 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2647,7 +2647,8 @@ public: void Destroy() { - mReferenceToThis = nullptr; + RefPtr referenceToThis; + mReferenceToThis.swap(referenceToThis); mValues.Clear(); mObjects.Clear(); mozilla::DropJSObjects(this); @@ -3489,6 +3490,8 @@ nsCycleCollector::nsCycleCollector() : nsCycleCollector::~nsCycleCollector() { + MOZ_ASSERT(!mJSPurpleBuffer, "Didn't call JSPurpleBuffer::Destroy?"); + UnregisterWeakMemoryReporter(this); } @@ -3989,6 +3992,10 @@ nsCycleCollector::Shutdown(bool aDoCollect) if (aDoCollect) { ShutdownCollect(); } + + if (mJSPurpleBuffer) { + mJSPurpleBuffer->Destroy(); + } } void From e1029c539425d0d1f7e7162ceccf183fb644a2a2 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:27 +0200 Subject: [PATCH 103/116] Bug 1466083 part 1 - Make IterateScripts take a realm instead of a compartment. r=luke --- js/src/gc/GC.h | 7 +- js/src/gc/PublicIterators.cpp | 9 +-- js/src/jsapi-tests/testPreserveJitCode.cpp | 2 +- js/src/vm/Debugger.cpp | 85 +++++++++++----------- 4 files changed, 49 insertions(+), 54 deletions(-) diff --git a/js/src/gc/GC.h b/js/src/gc/GC.h index 425c99d9e79b..d8e00f544c27 100644 --- a/js/src/gc/GC.h +++ b/js/src/gc/GC.h @@ -114,12 +114,11 @@ typedef void (*IterateScriptCallback)(JSRuntime* rt, void* data, JSScript* scrip const JS::AutoRequireNoGC& nogc); /* - * Invoke scriptCallback on every in-use script for - * the given compartment or for all compartments if it is null. + * Invoke scriptCallback on every in-use script for the given realm or for all + * realms if it is null. */ extern void -IterateScripts(JSContext* cx, JSCompartment* compartment, - void* data, IterateScriptCallback scriptCallback); +IterateScripts(JSContext* cx, JS::Realm* realm, void* data, IterateScriptCallback scriptCallback); JS::Realm* NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& options); diff --git a/js/src/gc/PublicIterators.cpp b/js/src/gc/PublicIterators.cpp index 1be49242381c..954aa8866b28 100644 --- a/js/src/gc/PublicIterators.cpp +++ b/js/src/gc/PublicIterators.cpp @@ -85,18 +85,17 @@ js::IterateChunks(JSContext* cx, void* data, IterateChunkCallback chunkCallback) } void -js::IterateScripts(JSContext* cx, JSCompartment* compartment, - void* data, IterateScriptCallback scriptCallback) +js::IterateScripts(JSContext* cx, Realm* realm, void* data, IterateScriptCallback scriptCallback) { MOZ_ASSERT(!cx->suppressGC); AutoEmptyNursery empty(cx); AutoPrepareForTracing prep(cx); JS::AutoSuppressGCAnalysis nogc; - if (compartment) { - Zone* zone = compartment->zone(); + if (realm) { + Zone* zone = realm->zone(); for (auto script = zone->cellIter(empty); !script.done(); script.next()) { - if (script->compartment() == compartment) + if (script->realm() == realm) scriptCallback(cx->runtime(), data, script, nogc); } } else { diff --git a/js/src/jsapi-tests/testPreserveJitCode.cpp b/js/src/jsapi-tests/testPreserveJitCode.cpp index 2406574b2443..96f263232fb9 100644 --- a/js/src/jsapi-tests/testPreserveJitCode.cpp +++ b/js/src/jsapi-tests/testPreserveJitCode.cpp @@ -28,7 +28,7 @@ unsigned countIonScripts(JSObject* global) { unsigned count = 0; - js::IterateScripts(cx, global->compartment(), &count, ScriptCallback); + js::IterateScripts(cx, global->realm(), &count, ScriptCallback); return count; } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 7f659fd9d83e..9108f88e869b 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4232,12 +4232,12 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery cx(cx), debugger(dbg), iterMarker(&cx->runtime()->gc), - compartments(cx->zone()), + realms(cx->zone()), url(cx), displayURLString(cx), hasSource(false), source(cx, AsVariant(static_cast(nullptr))), - innermostForCompartment(cx->zone()), + innermostForRealm(cx->zone()), vector(cx, ScriptVector(cx)), wasmInstanceVector(cx, WasmInstanceObjectVector(cx)) {} @@ -4247,8 +4247,8 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery * haven't enough memory. */ bool init() { - if (!compartments.init() || - !innermostForCompartment.init()) + if (!realms.init() || + !innermostForRealm.init()) { ReportOutOfMemory(cx); return false; @@ -4411,21 +4411,21 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery } /* - * Search all relevant compartments and the stack for scripts matching + * Search all relevant realms and the stack for scripts matching * this query, and append the matching scripts to |vector|. */ bool findScripts() { if (!prepareQuery() || !delazifyScripts()) return false; - JSCompartment* singletonComp = nullptr; - if (compartments.count() == 1) - singletonComp = compartments.all().front(); + Realm* singletonRealm = nullptr; + if (realms.count() == 1) + singletonRealm = realms.all().front(); - /* Search each compartment for debuggee scripts. */ + /* Search each realm for debuggee scripts. */ MOZ_ASSERT(vector.empty()); oom = false; - IterateScripts(cx, singletonComp, this, considerScript); + IterateScripts(cx, singletonRealm, this, considerScript); if (oom) { ReportOutOfMemory(cx); return false; @@ -4438,11 +4438,11 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery /* * For most queries, we just accumulate results in 'vector' as we find * them. But if this is an 'innermost' query, then we've accumulated the - * results in the 'innermostForCompartment' map. In that case, we now need to + * results in the 'innermostForRealm' map. In that case, we now need to * walk that map and populate 'vector'. */ if (innermost) { - for (CompartmentToScriptMap::Range r = innermostForCompartment.all(); + for (RealmToScriptMap::Range r = innermostForRealm.all(); !r.empty(); r.popFront()) { @@ -4484,14 +4484,13 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery /* The debugger for which we conduct queries. */ Debugger* debugger; - /* Require the set of compartments to stay fixed while the ScriptQuery is alive. */ + /* Require the set of realms to stay fixed while the ScriptQuery is alive. */ gc::AutoEnterIteration iterMarker; - typedef HashSet, ZoneAllocPolicy> - CompartmentSet; + using RealmSet = HashSet, ZoneAllocPolicy>; - /* A script must be in one of these compartments to match the query. */ - CompartmentSet compartments; + /* A script must be in one of these realms to match the query. */ + RealmSet realms; /* If this is a string, matching scripts have urls equal to it. */ RootedValue url; @@ -4520,15 +4519,14 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery /* True if the query has an 'innermost' property whose value is true. */ bool innermost; - typedef HashMap, ZoneAllocPolicy> - CompartmentToScriptMap; + using RealmToScriptMap = HashMap, ZoneAllocPolicy>; /* - * For 'innermost' queries, a map from compartments to the innermost script - * we've seen so far in that compartment. (Template instantiation code size + * For 'innermost' queries, a map from realms to the innermost script + * we've seen so far in that realm. (Template instantiation code size * explosion ho!) */ - CompartmentToScriptMap innermostForCompartment; + RealmToScriptMap innermostForRealm; /* * Accumulate the scripts in an Rooted, instead of creating @@ -4545,14 +4543,14 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery /* Indicates whether OOM has occurred while matching. */ bool oom; - bool addCompartment(JSCompartment* comp) { - return compartments.put(comp); + bool addRealm(Realm* realm) { + return realms.put(realm); } /* Arrange for this ScriptQuery to match only scripts that run in |global|. */ bool matchSingleGlobal(GlobalObject* global) { - MOZ_ASSERT(compartments.count() == 0); - if (!addCompartment(global->compartment())) { + MOZ_ASSERT(realms.count() == 0); + if (!addRealm(global->realm())) { ReportOutOfMemory(cx); return false; } @@ -4564,10 +4562,10 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery * globals. */ bool matchAllDebuggeeGlobals() { - MOZ_ASSERT(compartments.count() == 0); - /* Build our compartment set from the debugger's set of debuggee globals. */ + MOZ_ASSERT(realms.count() == 0); + /* Build our realm set from the debugger's set of debuggee globals. */ for (WeakGlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) { - if (!addCompartment(r.front()->compartment())) { + if (!addRealm(r.front()->realm())) { ReportOutOfMemory(cx); return false; } @@ -4591,11 +4589,10 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery } bool delazifyScripts() { - // All scripts in debuggee compartments must be visible, so delazify + // All scripts in debuggee realms must be visible, so delazify // everything. - for (auto r = compartments.all(); !r.empty(); r.popFront()) { - JSCompartment* comp = r.front(); - Realm* realm = JS::GetRealmForCompartment(comp); + for (auto r = realms.all(); !r.empty(); r.popFront()) { + Realm* realm = r.front(); if (!realm->ensureDelazifyScriptsForDebugger(cx)) return false; } @@ -4610,7 +4607,7 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery /* * If |script| matches this query, append it to |vector| or place it in - * |innermostForCompartment|, as appropriate. Set |oom| if an out of memory + * |innermostForRealm|, as appropriate. Set |oom| if an out of memory * condition occurred. */ void consider(JSScript* script, const JS::AutoRequireNoGC& nogc) { @@ -4619,8 +4616,8 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery // initialized from fullyInit{FromEmitter,Trivial} due to errors. if (oom || script->selfHosted() || !script->code()) return; - JSCompartment* compartment = script->compartment(); - if (!compartments.has(compartment)) + Realm* realm = script->realm(); + if (!realms.has(realm)) return; if (urlCString.ptr()) { bool gotFilename = false; @@ -4659,15 +4656,15 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery * For 'innermost' queries, we don't place scripts in |vector| right * away; we may later find another script that is nested inside this * one. Instead, we record the innermost script we've found so far - * for each compartment in innermostForCompartment, and only - * populate |vector| at the bottom of findScripts, when we've - * traversed all the scripts. + * for each realm in innermostForRealm, and only populate |vector| + * at the bottom of findScripts, when we've traversed all the + * scripts. * * So: check this script against the innermost one we've found so - * far (if any), as recorded in innermostForCompartment, and replace - * that if it's better. + * far (if any), as recorded in innermostForRealm, and replace that + * if it's better. */ - CompartmentToScriptMap::AddPtr p = innermostForCompartment.lookupForAdd(compartment); + RealmToScriptMap::AddPtr p = innermostForRealm.lookupForAdd(realm); if (p) { /* Is our newly found script deeper than the last one we found? */ JSScript* incumbent = p->value(); @@ -4679,9 +4676,9 @@ class MOZ_STACK_CLASS Debugger::ScriptQuery } else { /* * This is the first matching script we've encountered for this - * compartment, so it is thus the innermost such script. + * realm, so it is thus the innermost such script. */ - if (!innermostForCompartment.add(p, compartment, script)) { + if (!innermostForRealm.add(p, realm, script)) { oom = true; return; } From 030c2bbfd2ab65c43e2487fff4e3fedf98f14805 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:28 +0200 Subject: [PATCH 104/116] Bug 1466083 part 2 - Replace JSRuntime::numCompartments with JSRuntime::numRealms. r=luke --- js/src/proxy/CrossCompartmentWrapper.cpp | 5 ++--- js/src/vm/JSCompartment.cpp | 12 +++++------- js/src/vm/JSCompartment.h | 1 - js/src/vm/MemoryMetrics.cpp | 2 +- js/src/vm/Runtime.cpp | 2 +- js/src/vm/Runtime.h | 8 ++++---- 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/js/src/proxy/CrossCompartmentWrapper.cpp b/js/src/proxy/CrossCompartmentWrapper.cpp index 94d4cdcd2673..035ae0f467a9 100644 --- a/js/src/proxy/CrossCompartmentWrapper.cpp +++ b/js/src/proxy/CrossCompartmentWrapper.cpp @@ -678,13 +678,12 @@ js::RemapAllWrappersForObject(JSContext* cx, JSObject* oldTargetArg, RootedObject newTarget(cx, newTargetArg); AutoWrapperVector toTransplant(cx); - if (!toTransplant.reserve(cx->runtime()->numCompartments)) - return false; for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) { if (WrapperMap::Ptr wp = c->lookupWrapper(origv)) { // We found a wrapper. Remember and root it. - toTransplant.infallibleAppend(WrapperValue(wp)); + if (!toTransplant.append(WrapperValue(wp))) + return false; } } diff --git a/js/src/vm/JSCompartment.cpp b/js/src/vm/JSCompartment.cpp index 53cb42cb48e0..2cb05c8765a2 100644 --- a/js/src/vm/JSCompartment.cpp +++ b/js/src/vm/JSCompartment.cpp @@ -44,9 +44,7 @@ using mozilla::PodArrayZero; JSCompartment::JSCompartment(Zone* zone) : zone_(zone), runtime_(zone->runtimeFromAnyThread()) -{ - runtime_->numCompartments++; -} +{} ObjectRealm::ObjectRealm(JS::Zone* zone) : innerViews(zone) @@ -69,6 +67,8 @@ Realm::Realm(JS::Zone* zone, const JS::RealmOptions& options) { MOZ_ASSERT_IF(creationOptions_.mergeable(), creationOptions_.invisibleToDebugger()); + + runtime_->numRealms++; } Realm::~Realm() @@ -84,11 +84,9 @@ Realm::~Realm() if (!runtime_->gc.shutdownCollectedEverything()) objectGroups_.unboxedLayouts.clear(); #endif -} -JSCompartment::~JSCompartment() -{ - runtime_->numCompartments--; + MOZ_ASSERT(runtime_->numRealms > 0); + runtime_->numRealms--; } bool diff --git a/js/src/vm/JSCompartment.h b/js/src/vm/JSCompartment.h index 0b5e36c7b385..857ebc91f7d9 100644 --- a/js/src/vm/JSCompartment.h +++ b/js/src/vm/JSCompartment.h @@ -618,7 +618,6 @@ struct JSCompartment protected: explicit JSCompartment(JS::Zone* zone); - ~JSCompartment(); MOZ_MUST_USE bool init(JSContext* cx); diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index a314e12e817b..56c5fde2bfee 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -762,7 +762,7 @@ CollectRuntimeStatsHelper(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVis bool anonymize, IterateCellCallback statsCellCallback) { JSRuntime* rt = cx->runtime(); - if (!rtStats->realmStatsVector.reserve(rt->numCompartments)) + if (!rtStats->realmStatsVector.reserve(rt->numRealms)) return false; size_t totalZones = rt->gc.zones().length() + 1; // + 1 for the atoms zone. diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 430ad91088ad..ae8beb139bff 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -133,7 +133,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime) activeThreadHasScriptDataAccess(false), #endif numActiveHelperThreadZones(0), - numCompartments(0), + numRealms(0), localeCallbacks(nullptr), defaultLocale(nullptr), profilingScripts(false), diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 59ecc7182353..fec75795bc93 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -511,10 +511,10 @@ struct JSRuntime : public js::MallocProvider } #endif - // How many compartments there are across all zones. This number includes - // off thread context compartments, so it isn't necessarily equal to the - // number of compartments visited by CompartmentsIter. - js::MainThreadData numCompartments; + // How many realms there are across all zones. This number includes + // off-thread context realms, so it isn't necessarily equal to the + // number of realms visited by RealmsIter. + js::MainThreadData numRealms; /* Locale-specific callbacks for string conversion. */ js::MainThreadData localeCallbacks; From c72c47d1f145fa887fc08ba734549394bba75c6e Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:28 +0200 Subject: [PATCH 105/116] Bug 1466083 part 3 - Some minor Zone::sweepCompartments cleanup. r=jonco --- js/src/gc/GC.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index 688286b722ba..b58e210964a3 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -3830,38 +3830,37 @@ Zone::destroy(FreeOp* fop) } /* - * It's simpler if we preserve the invariant that every zone has at least one - * compartment. If we know we're deleting the entire zone, then - * SweepCompartments is allowed to delete all compartments. In this case, - * |keepAtleastOne| is false. If any cells remain alive in the zone, set - * |keepAtleastOne| true to prohibit sweepCompartments from deleting every - * compartment. Instead, it preserves an arbitrary compartment in the zone. + * It's simpler if we preserve the invariant that every zone (except the atoms + * zone) has at least one compartment, and every compartment has at least one + * realm. If we know we're deleting the entire zone, then sweepCompartments is + * allowed to delete all compartments. In this case, |keepAtleastOne| is false. + * If any cells remain alive in the zone, set |keepAtleastOne| true to prohibit + * sweepCompartments from deleting every compartment. Instead, it preserves an + * arbitrary compartment in the zone. */ void Zone::sweepCompartments(FreeOp* fop, bool keepAtleastOne, bool destroyingRuntime) { MOZ_ASSERT(!compartments().empty()); - - mozilla::DebugOnly rt = runtimeFromMainThread(); + MOZ_ASSERT_IF(destroyingRuntime, !keepAtleastOne); JSCompartment** read = compartments().begin(); JSCompartment** end = compartments().end(); JSCompartment** write = read; - bool foundOne = false; while (read < end) { JSCompartment* comp = *read++; Realm* realm = JS::GetRealmForCompartment(comp); /* - * Don't delete the last compartment and realm if all the ones before - * it were deleted and keepAtleastOne is true. + * Don't delete the last compartment and realm if keepAtleastOne is + * still true, meaning all the other compartments were deleted. */ - bool dontDelete = read == end && !foundOne && keepAtleastOne; - if ((!realm->marked() && !dontDelete) || destroyingRuntime) { - realm->destroy(fop); - } else { + bool dontDelete = read == end && keepAtleastOne; + if ((realm->marked() || dontDelete) && !destroyingRuntime) { *write++ = comp; - foundOne = true; + keepAtleastOne = false; + } else { + realm->destroy(fop); } } compartments().shrinkTo(write - compartments().begin()); From 907e63b5d13c85f9b6b31a6448517ed58c2007b8 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:28 +0200 Subject: [PATCH 106/116] Bug 1466083 part 4 - Use UniquePtr instead of ScopedJSDeletePtr when allocating Zones and Realms. r=jwalden --- js/src/gc/GC.cpp | 22 +++++++++++----------- js/src/jsapi.cpp | 4 +++- js/src/vm/Runtime.cpp | 5 ++--- js/src/vm/Stopwatch.cpp | 1 + 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/js/src/gc/GC.cpp b/js/src/gc/GC.cpp index b58e210964a3..157ccddf01f8 100644 --- a/js/src/gc/GC.cpp +++ b/js/src/gc/GC.cpp @@ -7939,7 +7939,7 @@ js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& op JSRuntime* rt = cx->runtime(); JS_AbortIfWrongThread(cx); - ScopedJSDeletePtr zoneHolder; + UniquePtr zoneHolder; Zone* zone = nullptr; JS::ZoneSpecifier zoneSpec = options.creationOptions().zoneSpecifier(); @@ -7958,29 +7958,29 @@ js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& op } if (!zone) { - zone = cx->new_(cx->runtime()); - if (!zone) + zoneHolder = cx->make_unique(cx->runtime()); + if (!zoneHolder) return nullptr; - zoneHolder.reset(zone); - const JSPrincipals* trusted = rt->trustedPrincipals(); bool isSystem = principals && principals == trusted; - if (!zone->init(isSystem)) { + if (!zoneHolder->init(isSystem)) { ReportOutOfMemory(cx); return nullptr; } + + zone = zoneHolder.get(); } - ScopedJSDeletePtr realm(cx->new_(zone, options)); + UniquePtr realm = cx->make_unique(zone, options); if (!realm || !realm->init(cx)) return nullptr; // Set up the principals. - JS::SetRealmPrincipals(realm, principals); + JS::SetRealmPrincipals(realm.get(), principals); JSCompartment* comp = realm->compartment(); - if (!comp->realms().append(realm)) { + if (!comp->realms().append(realm.get())) { ReportOutOfMemory(cx); return nullptr; } @@ -8006,8 +8006,8 @@ js::NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& op } } - zoneHolder.forget(); - return realm.forget(); + mozilla::Unused << zoneHolder.release(); + return realm.release(); } void diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 88ef5549b03a..519901cf9fd7 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3467,8 +3467,10 @@ JS_PUBLIC_API(void) JS_DropPrincipals(JSContext* cx, JSPrincipals* principals) { int rc = --principals->refcount; - if (rc == 0) + if (rc == 0) { + JS::AutoSuppressGCAnalysis nogc; cx->runtime()->destroyPrincipals(principals); + } } JS_PUBLIC_API(void) diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index ae8beb139bff..293eb8423b37 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -214,12 +214,11 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes) if (!gc.init(maxbytes, maxNurseryBytes)) return false; - ScopedJSDeletePtr atomsZone(js_new(this)); + UniquePtr atomsZone = MakeUnique(this); if (!atomsZone || !atomsZone->init(true)) return false; - gc.atomsZone = atomsZone.get(); - atomsZone.forget(); + gc.atomsZone = atomsZone.release(); if (!symbolRegistry_.ref().init()) return false; diff --git a/js/src/vm/Stopwatch.cpp b/js/src/vm/Stopwatch.cpp index 2dff6d2516b0..3d7a7aad695a 100644 --- a/js/src/vm/Stopwatch.cpp +++ b/js/src/vm/Stopwatch.cpp @@ -588,6 +588,7 @@ PerformanceGroup::Release() if (refCount_ > 0) return; + JS::AutoSuppressGCAnalysis nogc; this->Delete(); } From 85dfb1be7c993fd542fbe6d0db679f7f162bb42d Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:28 +0200 Subject: [PATCH 107/116] Bug 1466083 part 5 - Assume we have a single compartment/realm in Zone::deleteEmptyCompartment. r=jonco --- js/src/gc/Zone.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 93ef4926da08..5b5dab6bd266 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -394,14 +394,15 @@ Zone::deleteEmptyCompartment(JSCompartment* comp) { MOZ_ASSERT(comp->zone() == this); MOZ_ASSERT(arenas.checkEmptyArenaLists()); - for (auto& i : compartments()) { - if (i == comp) { - compartments().erase(&i); - JS::GetRealmForCompartment(comp)->destroy(runtimeFromMainThread()->defaultFreeOp()); - return; - } - } - MOZ_CRASH("Compartment not found"); + + MOZ_ASSERT(compartments().length() == 1); + MOZ_ASSERT(compartments()[0] == comp); + MOZ_ASSERT(comp->realms().length() == 1); + + Realm* realm = comp->realms()[0]; + realm->destroy(runtimeFromMainThread()->defaultFreeOp()); + + compartments().clear(); } void From 403ba762c80d961a8a07ae51223e46b56059d2fc Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Sat, 2 Jun 2018 11:58:29 +0200 Subject: [PATCH 108/116] Bug 1466083 part 6 - Add xpc::GetRealmPrincipal and use it in a few places. r=bz Not strictly necessary, but this lets us remove some JS::GetCompartmentForRealm and JS_GetCompartmentPrincipals calls. --- dom/base/nsContentUtils.cpp | 3 +-- dom/base/nsGlobalWindowOuter.cpp | 5 +---- js/xpconnect/src/xpcpublic.h | 1 + js/xpconnect/wrappers/AccessCheck.cpp | 6 ++++++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 1ffc7355c230..f9ab1405f6e3 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2367,8 +2367,7 @@ nsContentUtils::IsCallerContentXBL() // For remote XUL, we run XBL in the XUL scope. Given that we care about // compat and not security for remote XUL, just always claim to be XBL. if (!xpc::AllowContentXBLScope(realm)) { - DebugOnly c = JS::GetCompartmentForRealm(realm); - MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetCompartmentPrincipal(c))); + MOZ_ASSERT(nsContentUtils::AllowXULXBLForPrincipal(xpc::GetRealmPrincipal(realm))); return true; } diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index 9674a7ceeed6..3a3fb9cd3dde 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -1758,11 +1758,8 @@ nsGlobalWindowOuter::SetNewDocument(nsIDocument* aDocument, nsJSPrincipals::get(JS::GetRealmPrincipals(realm)); aDocument->NodePrincipal()->Equals(existing, &sameOrigin); MOZ_ASSERT(sameOrigin); - - JSCompartment* compartment = JS::GetCompartmentForRealm(realm); MOZ_ASSERT_IF(aDocument == oldDoc, - xpc::GetCompartmentPrincipal(compartment) == - aDocument->NodePrincipal()); + xpc::GetRealmPrincipal(realm) == aDocument->NodePrincipal()); #endif if (aDocument != oldDoc) { JS::SetRealmPrincipals(realm, diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 67a463e43c43..f5aa098bdc56 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -399,6 +399,7 @@ bool StringToJsval(JSContext* cx, mozilla::dom::DOMString& str, } nsIPrincipal* GetCompartmentPrincipal(JSCompartment* compartment); +nsIPrincipal* GetRealmPrincipal(JS::Realm* realm); void NukeAllWrappersForCompartment(JSContext* cx, JSCompartment* compartment, js::NukeReferencesToWindow nukeReferencesToWindow = js::NukeWindowReferences); diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index 7897f08da081..40f142c06954 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -36,6 +36,12 @@ GetCompartmentPrincipal(JSCompartment* compartment) return nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment)); } +nsIPrincipal* +GetRealmPrincipal(JS::Realm* realm) +{ + return nsJSPrincipals::get(JS::GetRealmPrincipals(realm)); +} + nsIPrincipal* GetObjectPrincipal(JSObject* obj) { From d64c4294ebb4d41f9939edcef0601b38d0e6359b Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:41 +0200 Subject: [PATCH 109/116] Bug 1466023 - Get rid of NS_GetStreamForBlobURI, r=qdot --- dom/file/nsHostObjectProtocolHandler.cpp | 18 ------------------ dom/file/nsHostObjectProtocolHandler.h | 3 --- dom/media/FileMediaResource.cpp | 15 ++++++++++++--- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/dom/file/nsHostObjectProtocolHandler.cpp b/dom/file/nsHostObjectProtocolHandler.cpp index 59bdfdd0cee0..055fa77cefe6 100644 --- a/dom/file/nsHostObjectProtocolHandler.cpp +++ b/dom/file/nsHostObjectProtocolHandler.cpp @@ -1040,24 +1040,6 @@ NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob) return NS_OK; } -nsresult -NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream) -{ - RefPtr blobImpl; - ErrorResult rv; - rv = NS_GetBlobForBlobURI(aURI, getter_AddRefs(blobImpl)); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - blobImpl->CreateInputStream(aStream, rv); - if (NS_WARN_IF(rv.Failed())) { - return rv.StealNSResult(); - } - - return NS_OK; -} - NS_IMETHODIMP nsFontTableProtocolHandler::NewURI(const nsACString& aSpec, const char *aCharset, diff --git a/dom/file/nsHostObjectProtocolHandler.h b/dom/file/nsHostObjectProtocolHandler.h index 1ac68e0530fc..29924ab1468d 100644 --- a/dom/file/nsHostObjectProtocolHandler.h +++ b/dom/file/nsHostObjectProtocolHandler.h @@ -132,9 +132,6 @@ NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::BlobImpl** aBlob, bool aAlsoIfR extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, mozilla::dom::BlobImpl** aBlob); -extern nsresult -NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream); - extern nsresult NS_GetSourceForMediaSourceURI(nsIURI* aURI, mozilla::dom::MediaSource** aSource); diff --git a/dom/media/FileMediaResource.cpp b/dom/media/FileMediaResource.cpp index d57ced7aa7ec..dd9827bbe69b 100644 --- a/dom/media/FileMediaResource.cpp +++ b/dom/media/FileMediaResource.cpp @@ -6,6 +6,7 @@ #include "FileMediaResource.h" #include "mozilla/AbstractThread.h" +#include "mozilla/dom/BlobImpl.h" #include "nsContentUtils.h" #include "nsHostObjectProtocolHandler.h" #include "nsIFileChannel.h" @@ -75,11 +76,19 @@ FileMediaResource::Open(nsIStreamListener** aStreamListener) rv = NS_NewLocalFileInputStream( getter_AddRefs(mInput), file, -1, -1, nsIFileInputStream::SHARE_DELETE); + NS_ENSURE_SUCCESS(rv, rv); } else if (IsBlobURI(mURI)) { - rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput)); - } + RefPtr blobImpl; + rv = NS_GetBlobForBlobURI(mURI, getter_AddRefs(blobImpl)); + NS_ENSURE_SUCCESS(rv, rv); + MOZ_ASSERT(blobImpl); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult err; + blobImpl->CreateInputStream(getter_AddRefs(mInput), err); + if (NS_WARN_IF(err.Failed())) { + return err.StealNSResult(); + } + } mSeekable = do_QueryInterface(mInput); if (!mSeekable) { From 426e4b7015e2e68b94172c7044cdcf4cc2041d17 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:41 +0200 Subject: [PATCH 110/116] Bug 1466023 - Remove an internal parameter only in NS_GetBlobForBlobURI, r=qdot --- dom/file/nsHostObjectProtocolHandler.cpp | 16 ++++++---------- dom/file/nsHostObjectProtocolHandler.h | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/dom/file/nsHostObjectProtocolHandler.cpp b/dom/file/nsHostObjectProtocolHandler.cpp index 055fa77cefe6..d6c7424f3ab6 100644 --- a/dom/file/nsHostObjectProtocolHandler.cpp +++ b/dom/file/nsHostObjectProtocolHandler.cpp @@ -891,12 +891,12 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri, { *result = nullptr; - RefPtr blobImpl; - NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl), true); - if (!blobImpl) { + DataInfo* info = GetDataInfoFromURI(uri, true /*aAlsoIfRevoked */); + if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) { return NS_ERROR_DOM_BAD_URI; } + RefPtr blobImpl = info->mBlobImpl; nsCOMPtr uriPrinc = do_QueryInterface(uri); if (!uriPrinc) { return NS_ERROR_DOM_BAD_URI; @@ -910,11 +910,7 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri, return NS_ERROR_DOM_BAD_URI; } -#ifdef DEBUG - // Info can be null, in case this blob URL has been revoked already. - DataInfo* info = GetDataInfoFromURI(uri); - MOZ_ASSERT_IF(info, info->mPrincipal == principal); -#endif + MOZ_ASSERT(info->mPrincipal == principal); // We want to be sure that we stop the creation of the channel if the blob URL // is copy-and-pasted on a different context (ex. private browsing or @@ -1011,11 +1007,11 @@ nsFontTableProtocolHandler::GetScheme(nsACString &result) } nsresult -NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob, bool aAlsoIfRevoked) +NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob) { *aBlob = nullptr; - DataInfo* info = GetDataInfoFromURI(aURI, aAlsoIfRevoked); + DataInfo* info = GetDataInfoFromURI(aURI, false /* aAlsoIfRevoked */); if (!info || info->mObjectType != DataInfo::eBlobImpl) { return NS_ERROR_DOM_BAD_URI; } diff --git a/dom/file/nsHostObjectProtocolHandler.h b/dom/file/nsHostObjectProtocolHandler.h index 29924ab1468d..bc47b45c54df 100644 --- a/dom/file/nsHostObjectProtocolHandler.h +++ b/dom/file/nsHostObjectProtocolHandler.h @@ -127,7 +127,7 @@ inline bool IsFontTableURI(nsIURI* aUri) } extern nsresult -NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::BlobImpl** aBlob, bool aAlsoIfRevoked = false); +NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::BlobImpl** aBlob); extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, mozilla::dom::BlobImpl** aBlob); From 7ba8b77e0795c0c8e5f993918d956d2ebc6e6504 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:42 +0200 Subject: [PATCH 111/116] Bug 1466023 - Separate FontTableURI and BlobURL, r=qdot This patch splits FontTableURI and BlobURL in 2 classes: FontTableURIProtocolHandler and BlobURLProtocolHandler both under mozilla::dom. It also removes a memory reporter because that report is already covered by the BlobURL one. --HG-- rename : dom/file/nsHostObjectProtocolHandler.cpp => dom/file/BlobURLProtocolHandler.cpp rename : dom/file/nsHostObjectProtocolHandler.h => dom/file/BlobURLProtocolHandler.h --- dom/base/nsContentUtils.cpp | 3 +- dom/base/nsDocument.cpp | 2 +- dom/base/nsIGlobalObject.cpp | 10 +- dom/fetch/FetchDriver.cpp | 2 +- ...Handler.cpp => BlobURLProtocolHandler.cpp} | 237 ++++++------------ ...ocolHandler.h => BlobURLProtocolHandler.h} | 61 ++--- dom/file/FontTableURIProtocolHandler.cpp | 154 ++++++++++++ dom/file/FontTableURIProtocolHandler.h | 45 ++++ dom/file/MutableBlobStorage.h | 1 + dom/file/MutableBlobStreamListener.cpp | 2 + dom/file/StreamBlobImpl.cpp | 3 + dom/file/moz.build | 6 +- dom/file/nsHostObjectURI.cpp | 2 +- dom/html/HTMLMediaElement.cpp | 2 +- dom/html/HTMLSourceElement.cpp | 3 +- dom/ipc/ContentChild.cpp | 21 +- dom/ipc/ContentParent.cpp | 14 +- dom/media/BaseMediaResource.cpp | 4 +- dom/media/FileMediaResource.cpp | 4 +- dom/url/URLMainThread.cpp | 14 +- dom/url/URLWorker.cpp | 10 +- dom/workers/ScriptLoader.cpp | 2 +- gfx/thebes/gfxSVGGlyphs.cpp | 6 +- image/ImageCacheKey.cpp | 2 +- layout/base/nsRefreshDriver.cpp | 4 +- layout/build/nsLayoutStatics.cpp | 4 +- 26 files changed, 351 insertions(+), 267 deletions(-) rename dom/file/{nsHostObjectProtocolHandler.cpp => BlobURLProtocolHandler.cpp} (78%) rename dom/file/{nsHostObjectProtocolHandler.h => BlobURLProtocolHandler.h} (60%) create mode 100644 dom/file/FontTableURIProtocolHandler.cpp create mode 100644 dom/file/FontTableURIProtocolHandler.h diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index f9ab1405f6e3..ad38558aa0e5 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -37,6 +37,7 @@ #include "mozilla/CheckedInt.h" #include "mozilla/DebugOnly.h" #include "mozilla/LoadInfo.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/MessageBroadcaster.h" @@ -49,6 +50,7 @@ #include "mozilla/dom/Event.h" #include "mozilla/dom/FileSystemSecurity.h" #include "mozilla/dom/FileBlobImpl.h" +#include "mozilla/dom/FontTableURIProtocolHandler.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSlotElement.h" #include "mozilla/dom/HTMLTemplateElement.h" @@ -111,7 +113,6 @@ #include "nsGenericHTMLElement.h" #include "nsGenericHTMLFrameElement.h" #include "nsGkAtoms.h" -#include "nsHostObjectProtocolHandler.h" #include "nsHtml5Module.h" #include "nsHtml5StringParser.h" #include "nsHTMLDocument.h" diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index d65dd301d03e..fa706f30cadd 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -127,7 +127,7 @@ #include "nsBindingManager.h" #include "nsHTMLDocument.h" #include "nsIRequest.h" -#include "nsHostObjectProtocolHandler.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "nsCharsetSource.h" #include "nsIParser.h" diff --git a/dom/base/nsIGlobalObject.cpp b/dom/base/nsIGlobalObject.cpp index 7d2125d4d391..0e0daf1f3c87 100644 --- a/dom/base/nsIGlobalObject.cpp +++ b/dom/base/nsIGlobalObject.cpp @@ -6,11 +6,11 @@ #include "nsIGlobalObject.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/ServiceWorker.h" #include "mozilla/dom/ServiceWorkerRegistration.h" #include "nsContentUtils.h" #include "nsThreadUtils.h" -#include "nsHostObjectProtocolHandler.h" using mozilla::MallocSizeOf; using mozilla::Maybe; @@ -67,7 +67,7 @@ public: MOZ_ASSERT(NS_IsMainThread()); for (uint32_t index = 0; index < mURIs.Length(); ++index) { - nsHostObjectProtocolHandler::RemoveDataEntry(mURIs[index]); + BlobURLProtocolHandler::RemoveDataEntry(mURIs[index]); } return NS_OK; @@ -90,14 +90,14 @@ nsIGlobalObject::UnlinkHostObjectURIs() if (NS_IsMainThread()) { for (uint32_t index = 0; index < mHostObjectURIs.Length(); ++index) { - nsHostObjectProtocolHandler::RemoveDataEntry(mHostObjectURIs[index]); + BlobURLProtocolHandler::RemoveDataEntry(mHostObjectURIs[index]); } mHostObjectURIs.Clear(); return; } - // nsHostObjectProtocolHandler is main-thread only. + // BlobURLProtocolHandler is main-thread only. RefPtr runnable = new UnlinkHostObjectURIsRunnable(mHostObjectURIs); @@ -123,7 +123,7 @@ nsIGlobalObject::TraverseHostObjectURIs(nsCycleCollectionTraversalCallback &aCb) } for (uint32_t index = 0; index < mHostObjectURIs.Length(); ++index) { - nsHostObjectProtocolHandler::Traverse(mHostObjectURIs[index], aCb); + BlobURLProtocolHandler::Traverse(mHostObjectURIs[index], aCb); } } diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 0abbf102e65a..23a1205833d4 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -22,7 +22,6 @@ #include "nsContentPolicyUtils.h" #include "nsDataHandler.h" -#include "nsHostObjectProtocolHandler.h" #include "nsNetUtil.h" #include "nsPrintfCString.h" #include "nsProxyRelease.h" @@ -30,6 +29,7 @@ #include "nsStringStream.h" #include "nsHttpChannel.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/File.h" #include "mozilla/dom/PerformanceStorage.h" #include "mozilla/dom/WorkerCommon.h" diff --git a/dom/file/nsHostObjectProtocolHandler.cpp b/dom/file/BlobURLProtocolHandler.cpp similarity index 78% rename from dom/file/nsHostObjectProtocolHandler.cpp rename to dom/file/BlobURLProtocolHandler.cpp index d6c7424f3ab6..7a151dc99ef0 100644 --- a/dom/file/nsHostObjectProtocolHandler.cpp +++ b/dom/file/BlobURLProtocolHandler.cpp @@ -4,7 +4,7 @@ * 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 "nsHostObjectProtocolHandler.h" +#include "BlobURLProtocolHandler.h" #include "mozilla/dom/ChromeUtils.h" #include "mozilla/dom/ContentChild.h" @@ -31,9 +31,11 @@ #define RELEASING_TIMER 5000 -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::ipc; +namespace mozilla { + +using namespace ipc; + +namespace dom { // ----------------------------------------------------------------------- // Hash table @@ -126,8 +128,6 @@ GetDataInfoFromURI(nsIURI* aURI, bool aAlsoIfRevoked = false) } // Memory reporting for the hash table. -namespace mozilla { - void BroadcastBlobURLRegistration(const nsACString& aURI, BlobImpl* aBlobImpl, @@ -168,28 +168,6 @@ BroadcastBlobURLUnregistration(const nsCString& aURI) Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(aURI)); } -class HostObjectURLsReporter final : public nsIMemoryReporter -{ - ~HostObjectURLsReporter() {} - - public: - NS_DECL_ISUPPORTS - - NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, - nsISupports* aData, bool aAnonymize) override - { - MOZ_COLLECT_REPORT( - "host-object-urls", KIND_OTHER, UNITS_COUNT, - gDataTable ? gDataTable->Count() : 0, - "The number of host objects stored for access via URLs " - "(e.g. blobs passed to URL.createObjectURL)."); - - return NS_OK; - } -}; - -NS_IMPL_ISUPPORTS(HostObjectURLsReporter, nsIMemoryReporter) - class BlobURLsReporter final : public nsIMemoryReporter { public: @@ -434,7 +412,7 @@ public: RefPtr holder = new ReleasingTimerHolder(aURI, aBroadcastToOtherProcesses); - auto raii = mozilla::MakeScopeExit([holder] { + auto raii = MakeScopeExit([holder] { holder->CancelTimerAndRevokeURI(); }); @@ -451,7 +429,7 @@ public: Run() override { RefPtr self = this; - auto raii = mozilla::MakeScopeExit([self] { + auto raii = MakeScopeExit([self] { self->CancelTimerAndRevokeURI(); }); @@ -580,8 +558,6 @@ private: NS_IMPL_ISUPPORTS_INHERITED(ReleasingTimerHolder, Runnable, nsITimerCallback, nsIAsyncShutdownBlocker) -} // namespace mozilla - template static nsresult AddDataEntryInternal(const nsACString& aURI, T aObject, @@ -592,33 +568,34 @@ AddDataEntryInternal(const nsACString& aURI, T aObject, } DataInfo* info = new DataInfo(aObject, aPrincipal); - mozilla::BlobURLsReporter::GetJSStackForBlob(info); + BlobURLsReporter::GetJSStackForBlob(info); gDataTable->Put(aURI, info); return NS_OK; } void -nsHostObjectProtocolHandler::Init(void) +BlobURLProtocolHandler::Init(void) { static bool initialized = false; if (!initialized) { initialized = true; - RegisterStrongMemoryReporter(new mozilla::HostObjectURLsReporter()); - RegisterStrongMemoryReporter(new mozilla::BlobURLsReporter()); + RegisterStrongMemoryReporter(new BlobURLsReporter()); } } -nsHostObjectProtocolHandler::nsHostObjectProtocolHandler() +BlobURLProtocolHandler::BlobURLProtocolHandler() { Init(); } +BlobURLProtocolHandler::~BlobURLProtocolHandler() = default; + /* static */ nsresult -nsHostObjectProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl, - nsIPrincipal* aPrincipal, - nsACString& aUri) +BlobURLProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl, + nsIPrincipal* aPrincipal, + nsACString& aUri) { Init(); @@ -633,9 +610,9 @@ nsHostObjectProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl, } /* static */ nsresult -nsHostObjectProtocolHandler::AddDataEntry(MediaSource* aMediaSource, - nsIPrincipal* aPrincipal, - nsACString& aUri) +BlobURLProtocolHandler::AddDataEntry(MediaSource* aMediaSource, + nsIPrincipal* aPrincipal, + nsACString& aUri) { Init(); @@ -649,17 +626,16 @@ nsHostObjectProtocolHandler::AddDataEntry(MediaSource* aMediaSource, } /* static */ nsresult -nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aURI, - nsIPrincipal* aPrincipal, - BlobImpl* aBlobImpl) +BlobURLProtocolHandler::AddDataEntry(const nsACString& aURI, + nsIPrincipal* aPrincipal, + BlobImpl* aBlobImpl) { return AddDataEntryInternal(aURI, aBlobImpl, aPrincipal); } /* static */ bool -nsHostObjectProtocolHandler::GetAllBlobURLEntries( - nsTArray& aRegistrations, - ContentParent* aCP) +BlobURLProtocolHandler::GetAllBlobURLEntries(nsTArray& aRegistrations, + ContentParent* aCP) { MOZ_ASSERT(aCP); @@ -692,8 +668,8 @@ nsHostObjectProtocolHandler::GetAllBlobURLEntries( } /*static */ void -nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri, - bool aBroadcastToOtherProcesses) +BlobURLProtocolHandler::RemoveDataEntry(const nsACString& aUri, + bool aBroadcastToOtherProcesses) { if (!gDataTable) { return; @@ -715,7 +691,7 @@ nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri, } /* static */ void -nsHostObjectProtocolHandler::RemoveDataEntries() +BlobURLProtocolHandler::RemoveDataEntries() { if (!gDataTable) { return; @@ -727,15 +703,15 @@ nsHostObjectProtocolHandler::RemoveDataEntries() } /* static */ bool -nsHostObjectProtocolHandler::HasDataEntry(const nsACString& aUri) +BlobURLProtocolHandler::HasDataEntry(const nsACString& aUri) { return !!GetDataInfo(aUri); } /* static */ nsresult -nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme, - nsIPrincipal* aPrincipal, - nsACString& aUri) +BlobURLProtocolHandler::GenerateURIString(const nsACString &aScheme, + nsIPrincipal* aPrincipal, + nsACString& aUri) { nsresult rv; nsCOMPtr uuidgen = @@ -769,15 +745,15 @@ nsHostObjectProtocolHandler::GenerateURIString(const nsACString &aScheme, } /* static */ nsresult -nsHostObjectProtocolHandler::GenerateURIStringForBlobURL(nsIPrincipal* aPrincipal, - nsACString& aUri) +BlobURLProtocolHandler::GenerateURIStringForBlobURL(nsIPrincipal* aPrincipal, + nsACString& aUri) { return GenerateURIString(NS_LITERAL_CSTRING(BLOBURI_SCHEME), aPrincipal, aUri); } /* static */ nsIPrincipal* -nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri) +BlobURLProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri) { if (!gDataTable) { return nullptr; @@ -793,8 +769,8 @@ nsHostObjectProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri) } /* static */ void -nsHostObjectProtocolHandler::Traverse(const nsACString& aUri, - nsCycleCollectionTraversalCallback& aCallback) +BlobURLProtocolHandler::Traverse(const nsACString& aUri, + nsCycleCollectionTraversalCallback& aCallback) { if (!gDataTable) { return; @@ -806,39 +782,36 @@ nsHostObjectProtocolHandler::Traverse(const nsACString& aUri, return; } - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mBlobImpl"); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "BlobURLProtocolHandler DataInfo.mBlobImpl"); aCallback.NoteXPCOMChild(res->mBlobImpl); - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "HostObjectProtocolHandler DataInfo.mMediaSource"); + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCallback, "BlobURLProtocolHandler DataInfo.mMediaSource"); aCallback.NoteXPCOMChild(res->mMediaSource); } -// ----------------------------------------------------------------------- -// Protocol handler - -NS_IMPL_ISUPPORTS(nsHostObjectProtocolHandler, nsIProtocolHandler, - nsISupportsWeakReference) +NS_IMPL_ISUPPORTS(BlobURLProtocolHandler, nsIProtocolHandler, + nsISupportsWeakReference) NS_IMETHODIMP -nsHostObjectProtocolHandler::GetDefaultPort(int32_t *result) +BlobURLProtocolHandler::GetDefaultPort(int32_t *result) { *result = -1; return NS_OK; } NS_IMETHODIMP -nsHostObjectProtocolHandler::GetProtocolFlags(uint32_t *result) +BlobURLProtocolHandler::GetProtocolFlags(uint32_t *result) { *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_SUBSUMERS | - URI_NON_PERSISTABLE; + URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE; return NS_OK; } NS_IMETHODIMP -nsHostObjectProtocolHandler::GetFlagsForURI(nsIURI *aURI, uint32_t *aResult) +BlobURLProtocolHandler::GetFlagsForURI(nsIURI *aURI, uint32_t *aResult) { - Unused << nsHostObjectProtocolHandler::GetProtocolFlags(aResult); - if (IsFontTableURI(aURI) || IsBlobURI(aURI)) { + Unused << BlobURLProtocolHandler::GetProtocolFlags(aResult); + if (IsBlobURI(aURI)) { *aResult |= URI_IS_LOCAL_RESOURCE; } @@ -846,18 +819,10 @@ nsHostObjectProtocolHandler::GetFlagsForURI(nsIURI *aURI, uint32_t *aResult) } NS_IMETHODIMP -nsBlobProtocolHandler::GetProtocolFlags(uint32_t *result) -{ - Unused << nsHostObjectProtocolHandler::GetProtocolFlags(result); - *result |= URI_IS_LOCAL_RESOURCE; - return NS_OK; -} - -NS_IMETHODIMP -nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec, - const char *aCharset, - nsIURI *aBaseURI, - nsIURI **aResult) +BlobURLProtocolHandler::NewURI(const nsACString& aSpec, + const char *aCharset, + nsIURI *aBaseURI, + nsIURI **aResult) { *aResult = nullptr; nsresult rv; @@ -865,7 +830,7 @@ nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec, DataInfo* info = GetDataInfo(aSpec); nsCOMPtr principal; - RefPtr blob; + RefPtr blob; if (info && info->mObjectType == DataInfo::eBlobImpl) { MOZ_ASSERT(info->mBlobImpl); principal = info->mPrincipal; @@ -885,9 +850,9 @@ nsHostObjectProtocolHandler::NewURI(const nsACString& aSpec, } NS_IMETHODIMP -nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri, - nsILoadInfo* aLoadInfo, - nsIChannel** result) +BlobURLProtocolHandler::NewChannel2(nsIURI* uri, + nsILoadInfo* aLoadInfo, + nsIChannel** result) { *result = nullptr; @@ -970,14 +935,14 @@ nsHostObjectProtocolHandler::NewChannel2(nsIURI* uri, } NS_IMETHODIMP -nsHostObjectProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +BlobURLProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) { return NewChannel2(uri, nullptr, result); } NS_IMETHODIMP -nsHostObjectProtocolHandler::AllowPort(int32_t port, const char *scheme, - bool *_retval) +BlobURLProtocolHandler::AllowPort(int32_t port, const char *scheme, + bool *_retval) { // don't override anything. *_retval = false; @@ -985,26 +950,14 @@ nsHostObjectProtocolHandler::AllowPort(int32_t port, const char *scheme, } NS_IMETHODIMP -nsBlobProtocolHandler::GetScheme(nsACString &result) +BlobURLProtocolHandler::GetScheme(nsACString &result) { result.AssignLiteral(BLOBURI_SCHEME); return NS_OK; } -NS_IMETHODIMP -nsFontTableProtocolHandler::GetProtocolFlags(uint32_t *result) -{ - Unused << nsHostObjectProtocolHandler::GetProtocolFlags(result); - *result |= URI_IS_LOCAL_RESOURCE; - return NS_OK; -} - -NS_IMETHODIMP -nsFontTableProtocolHandler::GetScheme(nsACString &result) -{ - result.AssignLiteral(FONTTABLEURI_SCHEME); - return NS_OK; -} +} // dom namespace +} // mozilla namespace nsresult NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob) @@ -1036,42 +989,6 @@ NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob) return NS_OK; } -NS_IMETHODIMP -nsFontTableProtocolHandler::NewURI(const nsACString& aSpec, - const char *aCharset, - nsIURI *aBaseURI, - nsIURI **aResult) -{ - nsresult rv; - nsCOMPtr uri; - - // Either you got here via a ref or a fonttable: uri - if (aSpec.Length() && aSpec.CharAt(0) == '#') { - rv = NS_MutateURI(aBaseURI) - .SetRef(aSpec) - .Finalize(uri); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // Relative URIs (other than #ref) are not meaningful within the - // fonttable: scheme. - // If aSpec is a relative URI -other- than a bare #ref, - // this will leave uri empty, and we'll return a failure code below. - rv = NS_MutateURI(new mozilla::net::nsSimpleURI::Mutator()) - .SetSpec(aSpec) - .Finalize(uri); - NS_ENSURE_SUCCESS(rv, rv); - } - - bool schemeIs; - if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) { - NS_WARNING("Non-fonttable spec in nsFontTableProtocolHander"); - return NS_ERROR_NOT_AVAILABLE; - } - - uri.forget(aResult); - return NS_OK; -} - nsresult NS_GetSourceForMediaSourceURI(nsIURI* aURI, MediaSource** aSource) { @@ -1087,39 +1004,34 @@ NS_GetSourceForMediaSourceURI(nsIURI* aURI, MediaSource** aSource) return NS_OK; } +namespace mozilla { +namespace dom { + #define NS_BLOBPROTOCOLHANDLER_CID \ { 0xb43964aa, 0xa078, 0x44b2, \ { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } } -#define NS_FONTTABLEPROTOCOLHANDLER_CID \ -{ 0x3fc8f04e, 0xd719, 0x43ca, \ - { 0x9a, 0xd0, 0x18, 0xee, 0x32, 0x02, 0x11, 0xf2 } } - -NS_GENERIC_FACTORY_CONSTRUCTOR(nsBlobProtocolHandler) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontTableProtocolHandler) +NS_GENERIC_FACTORY_CONSTRUCTOR(BlobURLProtocolHandler) NS_DEFINE_NAMED_CID(NS_BLOBPROTOCOLHANDLER_CID); -NS_DEFINE_NAMED_CID(NS_FONTTABLEPROTOCOLHANDLER_CID); -static const mozilla::Module::CIDEntry kHostObjectProtocolHandlerCIDs[] = { - { &kNS_BLOBPROTOCOLHANDLER_CID, false, nullptr, nsBlobProtocolHandlerConstructor }, - { &kNS_FONTTABLEPROTOCOLHANDLER_CID, false, nullptr, nsFontTableProtocolHandlerConstructor }, +static const Module::CIDEntry kBlobURLProtocolHandlerCIDs[] = { + { &kNS_BLOBPROTOCOLHANDLER_CID, false, nullptr, BlobURLProtocolHandlerConstructor }, { nullptr } }; -static const mozilla::Module::ContractIDEntry kHostObjectProtocolHandlerContracts[] = { +static const Module::ContractIDEntry kBlobURLProtocolHandlerContracts[] = { { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX BLOBURI_SCHEME, &kNS_BLOBPROTOCOLHANDLER_CID }, - { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX FONTTABLEURI_SCHEME, &kNS_FONTTABLEPROTOCOLHANDLER_CID }, { nullptr } }; -static const mozilla::Module kHostObjectProtocolHandlerModule = { - mozilla::Module::kVersion, - kHostObjectProtocolHandlerCIDs, - kHostObjectProtocolHandlerContracts +static const Module kBlobURLProtocolHandlerModule = { + Module::kVersion, + kBlobURLProtocolHandlerCIDs, + kBlobURLProtocolHandlerContracts }; -NSMODULE_DEFN(HostObjectProtocolHandler) = &kHostObjectProtocolHandlerModule; +NSMODULE_DEFN(BlobURLProtocolHandler) = &kBlobURLProtocolHandlerModule; bool IsType(nsIURI* aUri, DataInfo::ObjectType aType) { @@ -1140,3 +1052,6 @@ bool IsMediaSourceURI(nsIURI* aUri) { return IsType(aUri, DataInfo::eMediaSource); } + +} // dom namespace +} // mozilla namespace diff --git a/dom/file/nsHostObjectProtocolHandler.h b/dom/file/BlobURLProtocolHandler.h similarity index 60% rename from dom/file/nsHostObjectProtocolHandler.h rename to dom/file/BlobURLProtocolHandler.h index bc47b45c54df..c1c31dd9250d 100644 --- a/dom/file/nsHostObjectProtocolHandler.h +++ b/dom/file/BlobURLProtocolHandler.h @@ -4,8 +4,8 @@ * 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 nsHostObjectProtocolHandler_h -#define nsHostObjectProtocolHandler_h +#ifndef mozilla_dom_BlobURLProtocolHandler_h +#define mozilla_dom_BlobURLProtocolHandler_h #include "mozilla/Attributes.h" #include "nsIProtocolHandler.h" @@ -16,7 +16,6 @@ #include "nsWeakReference.h" #define BLOBURI_SCHEME "blob" -#define FONTTABLEURI_SCHEME "moz-fonttable" #define RTSPURI_SCHEME "rtsp" class nsIPrincipal; @@ -25,32 +24,22 @@ namespace mozilla { class BlobURLsReporter; namespace dom { + class BlobImpl; class BlobURLRegistrationData; class ContentParent; class MediaSource; -} // namespace dom -} // namespace mozilla -class nsHostObjectProtocolHandler : public nsIProtocolHandler - , public nsIProtocolHandlerWithDynamicFlags - , public nsSupportsWeakReference +class BlobURLProtocolHandler final : public nsIProtocolHandler + , public nsIProtocolHandlerWithDynamicFlags + , public nsSupportsWeakReference { public: - nsHostObjectProtocolHandler(); NS_DECL_ISUPPORTS + NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS - // nsIProtocolHandler methods, except for GetScheme which is only defined - // in subclasses. - NS_IMETHOD GetDefaultPort(int32_t *aDefaultPort) override; - NS_IMETHOD GetProtocolFlags(uint32_t *aProtocolFlags) override; - NS_IMETHOD NewURI(const nsACString & aSpec, const char * aOriginCharset, nsIURI *aBaseURI, nsIURI * *_retval) override; - NS_IMETHOD NewChannel2(nsIURI *aURI, nsILoadInfo *aLoadinfo, nsIChannel * *_retval) override; - NS_IMETHOD NewChannel(nsIURI *aURI, nsIChannel * *_retval) override; - NS_IMETHOD AllowPort(int32_t port, const char * scheme, bool *_retval) override; - - // nsIProtocolHandlerWithDynamicFlags methods - NS_IMETHOD GetFlagsForURI(nsIURI *aURI, uint32_t *aResult) override; + BlobURLProtocolHandler(); // If principal is not null, its origin will be used to generate the URI. static nsresult GenerateURIString(const nsACString &aScheme, @@ -86,31 +75,12 @@ public: GetAllBlobURLEntries(nsTArray& aRegistrations, mozilla::dom::ContentParent* aCP); -protected: - virtual ~nsHostObjectProtocolHandler() {} - private: + ~BlobURLProtocolHandler(); + static void Init(); }; -class nsBlobProtocolHandler : public nsHostObjectProtocolHandler -{ -public: - NS_IMETHOD GetProtocolFlags(uint32_t *aProtocolFlags) override; - NS_IMETHOD GetScheme(nsACString &result) override; -}; - -class nsFontTableProtocolHandler : public nsHostObjectProtocolHandler -{ -public: - NS_IMETHOD GetProtocolFlags(uint32_t *aProtocolFlags) override; - NS_IMETHOD GetScheme(nsACString &result) override; - NS_IMETHOD NewURI(const nsACString & aSpec, - const char *aOriginCharset, - nsIURI *aBaseURI, - nsIURI **_retval) override; -}; - bool IsBlobURI(nsIURI* aUri); bool IsMediaSourceURI(nsIURI* aUri); @@ -120,11 +90,8 @@ inline bool IsRtspURI(nsIURI* aUri) return NS_SUCCEEDED(aUri->SchemeIs(RTSPURI_SCHEME, &isRtsp)) && isRtsp; } -inline bool IsFontTableURI(nsIURI* aUri) -{ - bool isFont; - return NS_SUCCEEDED(aUri->SchemeIs(FONTTABLEURI_SCHEME, &isFont)) && isFont; -} +} // namespace dom +} // namespace mozilla extern nsresult NS_GetBlobForBlobURI(nsIURI* aURI, mozilla::dom::BlobImpl** aBlob); @@ -135,4 +102,4 @@ NS_GetBlobForBlobURISpec(const nsACString& aSpec, mozilla::dom::BlobImpl** aBlob extern nsresult NS_GetSourceForMediaSourceURI(nsIURI* aURI, mozilla::dom::MediaSource** aSource); -#endif /* nsHostObjectProtocolHandler_h */ +#endif /* mozilla_dom_BlobURLProtocolHandler_h */ diff --git a/dom/file/FontTableURIProtocolHandler.cpp b/dom/file/FontTableURIProtocolHandler.cpp new file mode 100644 index 000000000000..953a58ed2318 --- /dev/null +++ b/dom/file/FontTableURIProtocolHandler.cpp @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#include "FontTableURIProtocolHandler.h" +#include "mozilla/ModuleUtils.h" +#include "nsNetUtil.h" + +using namespace mozilla; +using namespace mozilla::dom; + +/* static */ nsresult +FontTableURIProtocolHandler::GenerateURIString(nsACString& aUri) +{ + nsresult rv; + nsCOMPtr uuidgen = + do_GetService("@mozilla.org/uuid-generator;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsID id; + rv = uuidgen->GenerateUUIDInPlace(&id); + NS_ENSURE_SUCCESS(rv, rv); + + char chars[NSID_LENGTH]; + id.ToProvidedString(chars); + + aUri = FONTTABLEURI_SCHEME; + aUri.Append(':'); + + aUri += Substring(chars + 1, chars + NSID_LENGTH - 2); + + return NS_OK; +} + +FontTableURIProtocolHandler::FontTableURIProtocolHandler() = default; +FontTableURIProtocolHandler::~FontTableURIProtocolHandler() = default; + +NS_IMPL_ISUPPORTS(FontTableURIProtocolHandler, nsIProtocolHandler, + nsISupportsWeakReference) + +NS_IMETHODIMP +FontTableURIProtocolHandler::GetDefaultPort(int32_t *result) +{ + *result = -1; + return NS_OK; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::GetProtocolFlags(uint32_t *result) +{ + *result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_SUBSUMERS | + URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE; + return NS_OK; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::GetFlagsForURI(nsIURI *aURI, uint32_t *aResult) +{ + return FontTableURIProtocolHandler::GetProtocolFlags(aResult); +} + + +NS_IMETHODIMP +FontTableURIProtocolHandler::NewChannel2(nsIURI* uri, + nsILoadInfo* aLoadInfo, + nsIChannel** result) +{ + return NS_ERROR_DOM_BAD_URI; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result) +{ + return NS_ERROR_DOM_BAD_URI; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::AllowPort(int32_t port, const char *scheme, + bool *_retval) +{ + *_retval = false; + return NS_OK; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::GetScheme(nsACString &result) +{ + result.AssignLiteral(FONTTABLEURI_SCHEME); + return NS_OK; +} + +NS_IMETHODIMP +FontTableURIProtocolHandler::NewURI(const nsACString& aSpec, + const char *aCharset, + nsIURI *aBaseURI, + nsIURI **aResult) +{ + nsresult rv; + nsCOMPtr uri; + + // Either you got here via a ref or a fonttable: uri + if (aSpec.Length() && aSpec.CharAt(0) == '#') { + rv = NS_MutateURI(aBaseURI) + .SetRef(aSpec) + .Finalize(uri); + NS_ENSURE_SUCCESS(rv, rv); + } else { + // Relative URIs (other than #ref) are not meaningful within the + // fonttable: scheme. + // If aSpec is a relative URI -other- than a bare #ref, + // this will leave uri empty, and we'll return a failure code below. + rv = NS_MutateURI(new mozilla::net::nsSimpleURI::Mutator()) + .SetSpec(aSpec) + .Finalize(uri); + NS_ENSURE_SUCCESS(rv, rv); + } + + bool schemeIs; + if (NS_FAILED(uri->SchemeIs(FONTTABLEURI_SCHEME, &schemeIs)) || !schemeIs) { + NS_WARNING("Non-fonttable spec in FontTableURIProtocolHandler"); + return NS_ERROR_NOT_AVAILABLE; + } + + uri.forget(aResult); + return NS_OK; +} + +#define NS_FONTTABLEPROTOCOLHANDLER_CID \ +{ 0x3fc8f04e, 0xd719, 0x43ca, \ + { 0x9a, 0xd0, 0x18, 0xee, 0x32, 0x02, 0x11, 0xf2 } } + +NS_GENERIC_FACTORY_CONSTRUCTOR(FontTableURIProtocolHandler) + +NS_DEFINE_NAMED_CID(NS_FONTTABLEPROTOCOLHANDLER_CID); + +static const mozilla::Module::CIDEntry FontTableURIProtocolHandlerCIDs[] = { + { &kNS_FONTTABLEPROTOCOLHANDLER_CID, false, nullptr, FontTableURIProtocolHandlerConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry FontTableURIProtocolHandlerContracts[] = { + { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX FONTTABLEURI_SCHEME, &kNS_FONTTABLEPROTOCOLHANDLER_CID }, + { nullptr } +}; + +static const mozilla::Module FontTableURIProtocolHandlerModule = { + mozilla::Module::kVersion, + FontTableURIProtocolHandlerCIDs, + FontTableURIProtocolHandlerContracts +}; + +NSMODULE_DEFN(FontTableURIProtocolHandler) = &FontTableURIProtocolHandlerModule; diff --git a/dom/file/FontTableURIProtocolHandler.h b/dom/file/FontTableURIProtocolHandler.h new file mode 100644 index 000000000000..7ccd1b5769e4 --- /dev/null +++ b/dom/file/FontTableURIProtocolHandler.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=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/. */ + +#ifndef FontTableURIProtocolHandler_h +#define FontTableURIProtocolHandler_h + +#include "nsIProtocolHandler.h" +#include "nsIURI.h" +#include "nsWeakReference.h" + +#define FONTTABLEURI_SCHEME "moz-fonttable" + +namespace mozilla { +namespace dom { + +class FontTableURIProtocolHandler final : public nsIProtocolHandler + , public nsIProtocolHandlerWithDynamicFlags + , public nsSupportsWeakReference +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPROTOCOLHANDLER + NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS + + FontTableURIProtocolHandler(); + + static nsresult GenerateURIString(nsACString &aUri); + +protected: + virtual ~FontTableURIProtocolHandler(); +}; + +inline bool IsFontTableURI(nsIURI* aUri) +{ + bool isFont; + return NS_SUCCEEDED(aUri->SchemeIs(FONTTABLEURI_SCHEME, &isFont)) && isFont; +} + +} // namespace dom +} // namespace mozilla + +#endif /* FontTableURIProtocolHandler_h */ diff --git a/dom/file/MutableBlobStorage.h b/dom/file/MutableBlobStorage.h index d2c7d25975b5..ab506ab79922 100644 --- a/dom/file/MutableBlobStorage.h +++ b/dom/file/MutableBlobStorage.h @@ -9,6 +9,7 @@ #include "mozilla/RefPtr.h" #include "mozilla/Mutex.h" +#include "nsCOMPtr.h" #include "prio.h" class nsIEventTarget; diff --git a/dom/file/MutableBlobStreamListener.cpp b/dom/file/MutableBlobStreamListener.cpp index 9487ded2d805..500a7a8e5705 100644 --- a/dom/file/MutableBlobStreamListener.cpp +++ b/dom/file/MutableBlobStreamListener.cpp @@ -6,6 +6,8 @@ #include "MutableBlobStreamListener.h" #include "MutableBlobStorage.h" +#include "nsIInputStream.h" +#include "nsThreadUtils.h" namespace mozilla { namespace dom { diff --git a/dom/file/StreamBlobImpl.cpp b/dom/file/StreamBlobImpl.cpp index 9a113626fb59..df840a6d36d7 100644 --- a/dom/file/StreamBlobImpl.cpp +++ b/dom/file/StreamBlobImpl.cpp @@ -4,7 +4,10 @@ * 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 "EmptyBlobImpl.h" +#include "mozilla/SlicedInputStream.h" #include "StreamBlobImpl.h" +#include "nsStreamUtils.h" #include "nsStringStream.h" #include "nsICloneableInputStream.h" diff --git a/dom/file/moz.build b/dom/file/moz.build index 66d8ffbf986d..a762d762ea16 100644 --- a/dom/file/moz.build +++ b/dom/file/moz.build @@ -10,7 +10,6 @@ with Files("**"): DIRS += ['ipc'] EXPORTS += [ - 'nsHostObjectProtocolHandler.h', 'nsHostObjectURI.h', ] @@ -19,12 +18,14 @@ EXPORTS.mozilla.dom += [ 'Blob.h', 'BlobImpl.h', 'BlobSet.h', + 'BlobURLProtocolHandler.h', 'File.h', 'FileBlobImpl.h', 'FileCreatorHelper.h', 'FileList.h', 'FileReader.h', 'FileReaderSync.h', + 'FontTableURIProtocolHandler.h', 'MemoryBlobImpl.h', 'MultipartBlobImpl.h', 'MutableBlobStorage.h', @@ -37,6 +38,7 @@ UNIFIED_SOURCES += [ 'Blob.cpp', 'BlobImpl.cpp', 'BlobSet.cpp', + 'BlobURLProtocolHandler.cpp', 'EmptyBlobImpl.cpp', 'File.cpp', 'FileBlobImpl.cpp', @@ -44,11 +46,11 @@ UNIFIED_SOURCES += [ 'FileList.cpp', 'FileReader.cpp', 'FileReaderSync.cpp', + 'FontTableURIProtocolHandler.cpp', 'MemoryBlobImpl.cpp', 'MultipartBlobImpl.cpp', 'MutableBlobStorage.cpp', 'MutableBlobStreamListener.cpp', - 'nsHostObjectProtocolHandler.cpp', 'nsHostObjectURI.cpp', 'StreamBlobImpl.cpp', 'StringBlobImpl.cpp', diff --git a/dom/file/nsHostObjectURI.cpp b/dom/file/nsHostObjectURI.cpp index 51f0094ffb36..aff83ec7e8fa 100644 --- a/dom/file/nsHostObjectURI.cpp +++ b/dom/file/nsHostObjectURI.cpp @@ -8,8 +8,8 @@ #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" -#include "nsHostObjectProtocolHandler.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/URIUtils.h" diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index d06348c2fbbb..554b0a90f179 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -58,6 +58,7 @@ #include "mozilla/Telemetry.h" #include "mozilla/dom/AudioTrack.h" #include "mozilla/dom/AudioTrackList.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/ElementInlines.h" #include "mozilla/dom/HTMLAudioElement.h" #include "mozilla/dom/HTMLInputElement.h" @@ -84,7 +85,6 @@ #include "nsError.h" #include "nsGenericHTMLElement.h" #include "nsGkAtoms.h" -#include "nsHostObjectProtocolHandler.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsICachingChannel.h" #include "nsICategoryManager.h" diff --git a/dom/html/HTMLSourceElement.cpp b/dom/html/HTMLSourceElement.cpp index cc3c6a462ecb..a1c3c96f7d64 100644 --- a/dom/html/HTMLSourceElement.cpp +++ b/dom/html/HTMLSourceElement.cpp @@ -15,8 +15,7 @@ #include "nsGkAtoms.h" -#include "nsHostObjectProtocolHandler.h" - +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/Preferences.h" NS_IMPL_NS_NEW_HTML_ELEMENT(Source) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index be3a01e0f11d..0cf37c555b15 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -162,7 +162,7 @@ #include "mozilla/dom/PCycleCollectWithLogsChild.h" #include "nsIScriptSecurityManager.h" -#include "nsHostObjectProtocolHandler.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #ifdef MOZ_WEBRTC #include "signaling/src/peerconnection/WebrtcGlobalChild.h" @@ -2367,7 +2367,7 @@ ContentChild::ActorDestroy(ActorDestroyReason why) gFirstIdleTask = nullptr; } - nsHostObjectProtocolHandler::RemoveDataEntries(); + BlobURLProtocolHandler::RemoveDataEntries(); mAlertObservers.Clear(); @@ -2765,15 +2765,14 @@ ContentChild::RecvInitBlobURLs(nsTArray&& aRegistration RefPtr blobImpl = IPCBlobUtils::Deserialize(registration.blob()); MOZ_ASSERT(blobImpl); - nsHostObjectProtocolHandler::AddDataEntry(registration.url(), - registration.principal(), - blobImpl); + BlobURLProtocolHandler::AddDataEntry(registration.url(), + registration.principal(), + blobImpl); // If we have received an already-revoked blobURL, we have to keep it alive - // for a while (see nsHostObjectProtocolHandler) in order to support pending + // for a while (see BlobURLProtocolHandler) in order to support pending // operations such as navigation, download and so on. if (registration.revoked()) { - nsHostObjectProtocolHandler::RemoveDataEntry(registration.url(), - false); + BlobURLProtocolHandler::RemoveDataEntry(registration.url(), false); } } @@ -3364,15 +3363,15 @@ ContentChild::RecvBlobURLRegistration(const nsCString& aURI, RefPtr blobImpl = IPCBlobUtils::Deserialize(aBlob); MOZ_ASSERT(blobImpl); - nsHostObjectProtocolHandler::AddDataEntry(aURI, aPrincipal, blobImpl); + BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, blobImpl); return IPC_OK(); } mozilla::ipc::IPCResult ContentChild::RecvBlobURLUnregistration(const nsCString& aURI) { - nsHostObjectProtocolHandler::RemoveDataEntry(aURI, - /* aBroadcastToOtherProcesses = */ false); + BlobURLProtocolHandler::RemoveDataEntry(aURI, + /* aBroadcastToOtherProcesses = */ false); return IPC_OK(); } diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index a6a8a31b553c..4098d8395093 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -184,6 +184,7 @@ #include "prio.h" #include "private/pprio.h" #include "ContentProcessManager.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/ipc/StructuredCloneData.h" #include "mozilla/PerformanceUtils.h" #include "mozilla/psm/PSMContentListener.h" @@ -192,7 +193,6 @@ #include "nsIBlocklistService.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" -#include "nsHostObjectProtocolHandler.h" #include "nsICaptivePortalService.h" #include "nsIObjectLoadingContent.h" #include "nsIBidiKeyboard.h" @@ -1802,7 +1802,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why) // Unregister all the BlobURLs registered by the ContentChild. for (uint32_t i = 0; i < mBlobURLs.Length(); ++i) { - nsHostObjectProtocolHandler::RemoveDataEntry(mBlobURLs[i]); + BlobURLProtocolHandler::RemoveDataEntry(mBlobURLs[i]); } mBlobURLs.Clear(); @@ -2468,8 +2468,7 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority) { nsTArray registrations; - if (nsHostObjectProtocolHandler::GetAllBlobURLEntries(registrations, - this)) { + if (BlobURLProtocolHandler::GetAllBlobURLEntries(registrations, this)) { for (const BlobURLRegistrationData& registration : registrations) { nsresult rv = TransmitPermissionsForPrincipal(registration.principal()); Unused << NS_WARN_IF(NS_FAILED(rv)); @@ -5192,8 +5191,8 @@ ContentParent::RecvStoreAndBroadcastBlobURLRegistration(const nsCString& aURI, return IPC_FAIL_NO_REASON(this); } - if (NS_SUCCEEDED(nsHostObjectProtocolHandler::AddDataEntry(aURI, aPrincipal, - blobImpl))) { + if (NS_SUCCEEDED(BlobURLProtocolHandler::AddDataEntry(aURI, aPrincipal, + blobImpl))) { BroadcastBlobURLRegistration(aURI, blobImpl, aPrincipal, this); // We want to store this blobURL, so we can unregister it if the child @@ -5208,8 +5207,7 @@ ContentParent::RecvStoreAndBroadcastBlobURLRegistration(const nsCString& aURI, mozilla::ipc::IPCResult ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) { - nsHostObjectProtocolHandler::RemoveDataEntry(aURI, - false /* Don't broadcast */); + BlobURLProtocolHandler::RemoveDataEntry(aURI, false /* Don't broadcast */); BroadcastBlobURLUnregistration(aURI, this); mBlobURLs.RemoveElement(aURI); diff --git a/dom/media/BaseMediaResource.cpp b/dom/media/BaseMediaResource.cpp index ef993c7149b8..54d98b39b627 100644 --- a/dom/media/BaseMediaResource.cpp +++ b/dom/media/BaseMediaResource.cpp @@ -5,10 +5,10 @@ #include "FileMediaResource.h" #include "MediaContainerType.h" #include "mozilla/dom/BlobImpl.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/HTMLMediaElement.h" #include "nsDebug.h" #include "nsError.h" -#include "nsHostObjectProtocolHandler.h" #include "nsICloneableInputStream.h" #include "nsIFile.h" #include "nsIFileChannel.h" @@ -50,7 +50,7 @@ BaseMediaResource::Create(MediaResourceCallback* aCallback, } RefPtr blobImpl; - if (IsBlobURI(uri) && + if (dom::IsBlobURI(uri) && NS_SUCCEEDED(NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl))) && blobImpl) { IgnoredErrorResult rv; diff --git a/dom/media/FileMediaResource.cpp b/dom/media/FileMediaResource.cpp index dd9827bbe69b..3a7920cf5ba9 100644 --- a/dom/media/FileMediaResource.cpp +++ b/dom/media/FileMediaResource.cpp @@ -7,8 +7,8 @@ #include "mozilla/AbstractThread.h" #include "mozilla/dom/BlobImpl.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "nsContentUtils.h" -#include "nsHostObjectProtocolHandler.h" #include "nsIFileChannel.h" #include "nsIFileStreams.h" #include "nsNetUtil.h" @@ -77,7 +77,7 @@ FileMediaResource::Open(nsIStreamListener** aStreamListener) rv = NS_NewLocalFileInputStream( getter_AddRefs(mInput), file, -1, -1, nsIFileInputStream::SHARE_DELETE); NS_ENSURE_SUCCESS(rv, rv); - } else if (IsBlobURI(mURI)) { + } else if (dom::IsBlobURI(mURI)) { RefPtr blobImpl; rv = NS_GetBlobForBlobURI(mURI, getter_AddRefs(blobImpl)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/url/URLMainThread.cpp b/dom/url/URLMainThread.cpp index c67f879ff924..2f79de386a0d 100644 --- a/dom/url/URLMainThread.cpp +++ b/dom/url/URLMainThread.cpp @@ -8,9 +8,9 @@ #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Blob.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/Unused.h" #include "nsContentUtils.h" -#include "nsHostObjectProtocolHandler.h" #include "nsIURL.h" #include "nsIURIMutator.h" #include "nsNetUtil.h" @@ -83,7 +83,7 @@ URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob, nsContentUtils::ObjectPrincipal(aGlobal.Get()); nsAutoCString url; - aRv = nsHostObjectProtocolHandler::AddDataEntry(aBlob.Impl(), principal, url); + aRv = BlobURLProtocolHandler::AddDataEntry(aBlob.Impl(), principal, url); if (NS_WARN_IF(aRv.Failed())) { return; } @@ -103,14 +103,14 @@ URLMainThread::CreateObjectURL(const GlobalObject& aGlobal, nsContentUtils::ObjectPrincipal(aGlobal.Get()); nsAutoCString url; - aRv = nsHostObjectProtocolHandler::AddDataEntry(&aSource, principal, url); + aRv = BlobURLProtocolHandler::AddDataEntry(&aSource, principal, url); if (NS_WARN_IF(aRv.Failed())) { return; } nsCOMPtr revocation = NS_NewRunnableFunction("dom::URLMainThread::CreateObjectURL", [url] { - nsHostObjectProtocolHandler::RemoveDataEntry(url); + BlobURLProtocolHandler::RemoveDataEntry(url); }); nsContentUtils::RunInStableState(revocation.forget()); @@ -134,11 +134,11 @@ URLMainThread::RevokeObjectURL(const GlobalObject& aGlobal, NS_LossyConvertUTF16toASCII asciiurl(aURL); nsIPrincipal* urlPrincipal = - nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl); + BlobURLProtocolHandler::GetDataEntryPrincipal(asciiurl); if (urlPrincipal && principal->Subsumes(urlPrincipal)) { global->UnregisterHostObjectURI(asciiurl); - nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl); + BlobURLProtocolHandler::RemoveDataEntry(asciiurl); } } @@ -159,7 +159,7 @@ URLMainThread::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL, { MOZ_ASSERT(NS_IsMainThread()); NS_LossyConvertUTF16toASCII asciiurl(aURL); - return nsHostObjectProtocolHandler::HasDataEntry(asciiurl); + return BlobURLProtocolHandler::HasDataEntry(asciiurl); } void diff --git a/dom/url/URLWorker.cpp b/dom/url/URLWorker.cpp index f677e8e01362..2eb27ef3b9c0 100644 --- a/dom/url/URLWorker.cpp +++ b/dom/url/URLWorker.cpp @@ -7,11 +7,11 @@ #include "URLWorker.h" #include "mozilla/dom/Blob.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerRunnable.h" #include "mozilla/dom/WorkerScope.h" #include "mozilla/Unused.h" -#include "nsHostObjectProtocolHandler.h" #include "nsProxyRelease.h" #include "nsStandardURL.h" #include "nsURLHelper.h" @@ -59,7 +59,7 @@ public: nsAutoCString url; nsresult rv = - nsHostObjectProtocolHandler::AddDataEntry(mBlobImpl, principal, url); + BlobURLProtocolHandler::AddDataEntry(mBlobImpl, principal, url); if (NS_FAILED(rv)) { NS_WARNING("Failed to add data entry for the blob!"); @@ -112,7 +112,7 @@ public: NS_ConvertUTF16toUTF8 url(mURL); nsIPrincipal* urlPrincipal = - nsHostObjectProtocolHandler::GetDataEntryPrincipal(url); + BlobURLProtocolHandler::GetDataEntryPrincipal(url); nsCOMPtr principal = mWorkerPrivate->GetPrincipal(); @@ -120,7 +120,7 @@ public: if (urlPrincipal && NS_SUCCEEDED(principal->Subsumes(urlPrincipal, &subsumes)) && subsumes) { - nsHostObjectProtocolHandler::RemoveDataEntry(url); + BlobURLProtocolHandler::RemoveDataEntry(url); } if (!mWorkerPrivate->IsSharedWorker() && @@ -167,7 +167,7 @@ public: AssertIsOnMainThread(); NS_ConvertUTF16toUTF8 url(mURL); - mValid = nsHostObjectProtocolHandler::HasDataEntry(url); + mValid = BlobURLProtocolHandler::HasDataEntry(url); return true; } diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index e7a87b8bfb37..cc7d9c751544 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -29,7 +29,6 @@ #include "nsContentPolicyUtils.h" #include "nsContentUtils.h" #include "nsDocShellCID.h" -#include "nsHostObjectProtocolHandler.h" #include "nsISupportsPrimitives.h" #include "nsNetUtil.h" #include "nsIPipe.h" @@ -46,6 +45,7 @@ #include "mozilla/LoadContext.h" #include "mozilla/Maybe.h" #include "mozilla/ipc/BackgroundUtils.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/CacheBinding.h" #include "mozilla/dom/cache/CacheTypes.h" #include "mozilla/dom/cache/Cache.h" diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp index 89be6eec1f1f..a28824d2eea8 100644 --- a/gfx/thebes/gfxSVGGlyphs.cpp +++ b/gfx/thebes/gfxSVGGlyphs.cpp @@ -22,10 +22,10 @@ #include "nsIPrincipal.h" #include "mozilla/BasePrincipal.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/FontTableURIProtocolHandler.h" #include "mozilla/dom/SVGDocument.h" #include "mozilla/LoadInfo.h" #include "nsSVGUtils.h" -#include "nsHostObjectProtocolHandler.h" #include "nsContentUtils.h" #include "gfxFont.h" #include "nsSMILAnimationController.h" @@ -351,9 +351,7 @@ gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen) NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr uri; - nsHostObjectProtocolHandler::GenerateURIString(NS_LITERAL_CSTRING(FONTTABLEURI_SCHEME), - nullptr, - mSVGGlyphsDocumentURI); + mozilla::dom::FontTableURIProtocolHandler::GenerateURIString(mSVGGlyphsDocumentURI); rv = NS_NewURI(getter_AddRefs(uri), mSVGGlyphsDocumentURI); NS_ENSURE_SUCCESS(rv, rv); diff --git a/image/ImageCacheKey.cpp b/image/ImageCacheKey.cpp index f14a2e0f485d..ac200c7b1520 100644 --- a/image/ImageCacheKey.cpp +++ b/image/ImageCacheKey.cpp @@ -7,9 +7,9 @@ #include "mozilla/Move.h" #include "ImageURL.h" -#include "nsHostObjectProtocolHandler.h" #include "nsLayoutUtils.h" #include "nsString.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/dom/File.h" #include "mozilla/dom/ServiceWorkerManager.h" #include "nsIDocument.h" diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 2c5085f6fceb..995fa14daee3 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -31,7 +31,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/AutoRestore.h" #include "mozilla/IntegerRange.h" -#include "nsHostObjectProtocolHandler.h" +#include "mozilla/dom/FontTableURIProtocolHandler.h" #include "nsITimer.h" #include "nsLayoutUtils.h" #include "nsPresContext.h" @@ -1347,7 +1347,7 @@ nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags) // XXXdholbert Exclude SVG-in-opentype fonts from this optimization, until // they receive refresh-driver ticks from their client docs (bug 1107252). nsIURI* uri = mPresContext->Document()->GetDocumentURI(); - if (!uri || !IsFontTableURI(uri)) { + if (!uri || !mozilla::dom::IsFontTableURI(uri)) { MOZ_ASSERT(!mActiveTimer, "image doc refresh driver should never have its own timer"); return; diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 4348fce7765b..f72afd47b5d2 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -109,7 +109,7 @@ #include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h" #include "mozilla/dom/U2FTokenManager.h" #include "mozilla/dom/PointerEventHandler.h" -#include "nsHostObjectProtocolHandler.h" +#include "mozilla/dom/BlobURLProtocolHandler.h" #include "nsThreadManager.h" using namespace mozilla; @@ -392,5 +392,5 @@ nsLayoutStatics::Shutdown() PromiseDebugging::Shutdown(); - nsHostObjectProtocolHandler::RemoveDataEntries(); + BlobURLProtocolHandler::RemoveDataEntries(); } From 962ddd487201ff80de0122ce62e74ba3fb0f7847 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:42 +0200 Subject: [PATCH 112/116] Bug 1466023 - Get rid of RTSP scheme, r=qdot --- dom/file/BlobURLProtocolHandler.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dom/file/BlobURLProtocolHandler.h b/dom/file/BlobURLProtocolHandler.h index c1c31dd9250d..4618b5475772 100644 --- a/dom/file/BlobURLProtocolHandler.h +++ b/dom/file/BlobURLProtocolHandler.h @@ -16,7 +16,6 @@ #include "nsWeakReference.h" #define BLOBURI_SCHEME "blob" -#define RTSPURI_SCHEME "rtsp" class nsIPrincipal; @@ -84,12 +83,6 @@ private: bool IsBlobURI(nsIURI* aUri); bool IsMediaSourceURI(nsIURI* aUri); -inline bool IsRtspURI(nsIURI* aUri) -{ - bool isRtsp; - return NS_SUCCEEDED(aUri->SchemeIs(RTSPURI_SCHEME, &isRtsp)) && isRtsp; -} - } // namespace dom } // namespace mozilla From d13a49eca5345c512408688faf9036d08d9a931f Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:42 +0200 Subject: [PATCH 113/116] Bug 1466023 - nsHostObjectURI renamed BlobURL, r=qdot --HG-- rename : dom/file/nsHostObjectURI.cpp => dom/file/BlobURL.cpp rename : dom/file/nsHostObjectURI.h => dom/file/BlobURL.h --- dom/file/{nsHostObjectURI.cpp => BlobURL.cpp} | 65 ++++++++++--------- dom/file/{nsHostObjectURI.h => BlobURL.h} | 43 +++++++----- dom/file/BlobURLProtocolHandler.cpp | 4 +- dom/file/MutableBlobStorage.cpp | 1 + dom/file/moz.build | 7 +- ipc/glue/URIUtils.cpp | 4 +- layout/build/nsLayoutModule.cpp | 10 +-- 7 files changed, 70 insertions(+), 64 deletions(-) rename dom/file/{nsHostObjectURI.cpp => BlobURL.cpp} (78%) rename dom/file/{nsHostObjectURI.h => BlobURL.h} (84%) diff --git a/dom/file/nsHostObjectURI.cpp b/dom/file/BlobURL.cpp similarity index 78% rename from dom/file/nsHostObjectURI.cpp rename to dom/file/BlobURL.cpp index aff83ec7e8fa..64e9ccf8477c 100644 --- a/dom/file/nsHostObjectURI.cpp +++ b/dom/file/BlobURL.cpp @@ -4,24 +4,25 @@ * 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 "nsHostObjectURI.h" - #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" +#include "mozilla/dom/BlobURL.h" #include "mozilla/dom/BlobURLProtocolHandler.h" #include "mozilla/ipc/BackgroundUtils.h" #include "mozilla/ipc/URIUtils.h" +using namespace mozilla::dom; + static NS_DEFINE_CID(kHOSTOBJECTURICID, NS_HOSTOBJECTURI_CID); static NS_DEFINE_CID(kThisSimpleURIImplementationCID, NS_THIS_SIMPLEURI_IMPLEMENTATION_CID); -NS_IMPL_ADDREF_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI) -NS_IMPL_RELEASE_INHERITED(nsHostObjectURI, mozilla::net::nsSimpleURI) +NS_IMPL_ADDREF_INHERITED(BlobURL, mozilla::net::nsSimpleURI) +NS_IMPL_RELEASE_INHERITED(BlobURL, mozilla::net::nsSimpleURI) -NS_INTERFACE_MAP_BEGIN(nsHostObjectURI) +NS_INTERFACE_MAP_BEGIN(BlobURL) NS_INTERFACE_MAP_ENTRY(nsIURIWithPrincipal) if (aIID.Equals(kHOSTOBJECTURICID)) foundInterface = static_cast(this); @@ -38,7 +39,7 @@ NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI) // nsIURIWithPrincipal methods: NS_IMETHODIMP -nsHostObjectURI::GetPrincipal(nsIPrincipal** aPrincipal) +BlobURL::GetPrincipal(nsIPrincipal** aPrincipal) { MOZ_ASSERT(NS_IsMainThread()); nsCOMPtr principal = mPrincipal.get(); @@ -48,7 +49,7 @@ nsHostObjectURI::GetPrincipal(nsIPrincipal** aPrincipal) } NS_IMETHODIMP -nsHostObjectURI::GetPrincipalUri(nsIURI** aUri) +BlobURL::GetPrincipalUri(nsIURI** aUri) { if (mPrincipal) { mPrincipal->GetURI(aUri); @@ -63,14 +64,14 @@ nsHostObjectURI::GetPrincipalUri(nsIURI** aUri) // nsISerializable methods: NS_IMETHODIMP -nsHostObjectURI::Read(nsIObjectInputStream* aStream) +BlobURL::Read(nsIObjectInputStream* aStream) { NS_NOTREACHED("Use nsIURIMutator.read() instead"); return NS_ERROR_NOT_IMPLEMENTED; } nsresult -nsHostObjectURI::ReadPrivate(nsIObjectInputStream *aStream) +BlobURL::ReadPrivate(nsIObjectInputStream *aStream) { nsresult rv = mozilla::net::nsSimpleURI::ReadPrivate(aStream); NS_ENSURE_SUCCESS(rv, rv); @@ -85,7 +86,7 @@ nsHostObjectURI::ReadPrivate(nsIObjectInputStream *aStream) } NS_IMETHODIMP -nsHostObjectURI::Write(nsIObjectOutputStream* aStream) +BlobURL::Write(nsIObjectOutputStream* aStream) { nsresult rv = mozilla::net::nsSimpleURI::Write(aStream); NS_ENSURE_SUCCESS(rv, rv); @@ -98,7 +99,7 @@ nsHostObjectURI::Write(nsIObjectOutputStream* aStream) // nsIIPCSerializableURI methods: void -nsHostObjectURI::Serialize(mozilla::ipc::URIParams& aParams) +BlobURL::Serialize(mozilla::ipc::URIParams& aParams) { using namespace mozilla::ipc; @@ -125,7 +126,7 @@ nsHostObjectURI::Serialize(mozilla::ipc::URIParams& aParams) } bool -nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams) +BlobURL::Deserialize(const mozilla::ipc::URIParams& aParams) { using namespace mozilla::ipc; @@ -154,7 +155,7 @@ nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams) } nsresult -nsHostObjectURI::SetScheme(const nsACString& aScheme) +BlobURL::SetScheme(const nsACString& aScheme) { // Disallow setting the scheme, since that could cause us to be associated // with a different protocol handler that doesn't expect us to be carrying @@ -164,9 +165,9 @@ nsHostObjectURI::SetScheme(const nsACString& aScheme) // nsIURI methods: nsresult -nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode, - const nsACString& newRef, - nsIURI** aClone) +BlobURL::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode, + const nsACString& newRef, + nsIURI** aClone) { nsCOMPtr simpleClone; nsresult rv = @@ -174,12 +175,12 @@ nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHa NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG - RefPtr uriCheck; + RefPtr uriCheck; rv = simpleClone->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(uriCheck)); MOZ_ASSERT(NS_SUCCEEDED(rv) && uriCheck); #endif - nsHostObjectURI* u = static_cast(simpleClone.get()); + BlobURL* u = static_cast(simpleClone.get()); u->mPrincipal = mPrincipal; @@ -188,16 +189,16 @@ nsHostObjectURI::CloneInternal(mozilla::net::nsSimpleURI::RefHandlingEnum aRefHa } /* virtual */ nsresult -nsHostObjectURI::EqualsInternal(nsIURI* aOther, - mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode, - bool* aResult) +BlobURL::EqualsInternal(nsIURI* aOther, + mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode, + bool* aResult) { if (!aOther) { *aResult = false; return NS_OK; } - RefPtr otherUri; + RefPtr otherUri; aOther->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(otherUri)); if (!otherUri) { *aResult = false; @@ -220,16 +221,16 @@ nsHostObjectURI::EqualsInternal(nsIURI* aOther, } // Queries this list of interfaces. If none match, it queries mURI. -NS_IMPL_NSIURIMUTATOR_ISUPPORTS(nsHostObjectURI::Mutator, +NS_IMPL_NSIURIMUTATOR_ISUPPORTS(BlobURL::Mutator, nsIURISetters, nsIURIMutator, nsIPrincipalURIMutator, nsISerializable) NS_IMETHODIMP -nsHostObjectURI::Mutate(nsIURIMutator** aMutator) +BlobURL::Mutate(nsIURIMutator** aMutator) { - RefPtr mutator = new nsHostObjectURI::Mutator(); + RefPtr mutator = new BlobURL::Mutator(); nsresult rv = mutator->InitFromURI(this); if (NS_FAILED(rv)) { return rv; @@ -240,7 +241,7 @@ nsHostObjectURI::Mutate(nsIURIMutator** aMutator) // nsIClassInfo methods: NS_IMETHODIMP -nsHostObjectURI::GetInterfaces(uint32_t *count, nsIID * **array) +BlobURL::GetInterfaces(uint32_t *count, nsIID * **array) { *count = 0; *array = nullptr; @@ -248,14 +249,14 @@ nsHostObjectURI::GetInterfaces(uint32_t *count, nsIID * **array) } NS_IMETHODIMP -nsHostObjectURI::GetScriptableHelper(nsIXPCScriptable **_retval) +BlobURL::GetScriptableHelper(nsIXPCScriptable **_retval) { *_retval = nullptr; return NS_OK; } NS_IMETHODIMP -nsHostObjectURI::GetContractID(nsACString& aContractID) +BlobURL::GetContractID(nsACString& aContractID) { // Make sure to modify any subclasses as needed if this ever // changes. @@ -264,14 +265,14 @@ nsHostObjectURI::GetContractID(nsACString& aContractID) } NS_IMETHODIMP -nsHostObjectURI::GetClassDescription(nsACString& aClassDescription) +BlobURL::GetClassDescription(nsACString& aClassDescription) { aClassDescription.SetIsVoid(true); return NS_OK; } NS_IMETHODIMP -nsHostObjectURI::GetClassID(nsCID * *aClassID) +BlobURL::GetClassID(nsCID * *aClassID) { // Make sure to modify any subclasses as needed if this ever // changes to not call the virtual GetClassIDNoAlloc. @@ -282,14 +283,14 @@ nsHostObjectURI::GetClassID(nsCID * *aClassID) } NS_IMETHODIMP -nsHostObjectURI::GetFlags(uint32_t *aFlags) +BlobURL::GetFlags(uint32_t *aFlags) { *aFlags = nsIClassInfo::MAIN_THREAD_ONLY; return NS_OK; } NS_IMETHODIMP -nsHostObjectURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) +BlobURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) { *aClassIDNoAlloc = kHOSTOBJECTURICID; return NS_OK; diff --git a/dom/file/nsHostObjectURI.h b/dom/file/BlobURL.h similarity index 84% rename from dom/file/nsHostObjectURI.h rename to dom/file/BlobURL.h index 44ad9be39e9f..821e00fa4414 100644 --- a/dom/file/nsHostObjectURI.h +++ b/dom/file/BlobURL.h @@ -4,8 +4,8 @@ * 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 nsHostObjectURI_h -#define nsHostObjectURI_h +#ifndef mozilla_dom_BlobURL_h +#define mozilla_dom_BlobURL_h #include "mozilla/Attributes.h" #include "mozilla/dom/File.h" @@ -18,23 +18,26 @@ #include "nsIIPCSerializableURI.h" #include "nsProxyRelease.h" +namespace mozilla { +namespace dom { + /** - * These URIs refer to host objects with "blob" scheme. The underlying objects - * can be Blobs or MediaSources. + * These URIs refer to host objects with "blob" scheme. The underlying object is + * a BlobImpl. */ -class nsHostObjectURI final +class BlobURL final : public mozilla::net::nsSimpleURI , public nsIURIWithPrincipal { private: - explicit nsHostObjectURI(nsIPrincipal* aPrincipal) + explicit BlobURL(nsIPrincipal* aPrincipal) : mozilla::net::nsSimpleURI() { mPrincipal = new nsMainThreadPtrHolder("nsIPrincipal", aPrincipal, false); } // For use only from deserialization - explicit nsHostObjectURI() + explicit BlobURL() : mozilla::net::nsSimpleURI() {} @@ -53,11 +56,11 @@ public: RefHandlingEnum aRefHandlingMode, bool* aResult) override; - // Override StartClone to hand back a nsHostObjectURI + // Override StartClone to hand back a BlobURL virtual mozilla::net::nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode, const nsACString& newRef) override { - nsHostObjectURI* url = new nsHostObjectURI(); + BlobURL* url = new BlobURL(); SetRefOnClone(url, refHandlingMode, newRef); return url; } @@ -66,8 +69,8 @@ public: nsMainThreadPtrHandle mPrincipal; -protected: - virtual ~nsHostObjectURI() {} +private: + virtual ~BlobURL() = default; nsresult SetScheme(const nsACString &aProtocol) override; bool Deserialize(const mozilla::ipc::URIParams&); @@ -76,7 +79,7 @@ protected: public: class Mutator final : public nsIURIMutator - , public BaseURIMutator + , public BaseURIMutator , public nsIPrincipalURIMutator , public nsISerializable { @@ -107,14 +110,15 @@ public: return NS_OK; } - explicit Mutator() { } - private: - virtual ~Mutator() { } + Mutator() = default; - friend class nsHostObjectURI; + private: + ~Mutator() = default; + + friend class BlobURL; }; - friend BaseURIMutator; + friend BaseURIMutator; }; #define NS_HOSTOBJECTURI_CID \ @@ -125,4 +129,7 @@ public: { 0xbbe50ef2, 0x80eb, 0x469d, \ { 0xb7, 0x0d, 0x02, 0x85, 0x82, 0x75, 0x38, 0x9f } } -#endif /* nsHostObjectURI_h */ +} // dom namespace +} // mozilla namespace + +#endif /* mozilla_dom_BlobURL_h */ diff --git a/dom/file/BlobURLProtocolHandler.cpp b/dom/file/BlobURLProtocolHandler.cpp index 7a151dc99ef0..57e1a88bd1ce 100644 --- a/dom/file/BlobURLProtocolHandler.cpp +++ b/dom/file/BlobURLProtocolHandler.cpp @@ -6,6 +6,7 @@ #include "BlobURLProtocolHandler.h" +#include "mozilla/dom/BlobURL.h" #include "mozilla/dom/ChromeUtils.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/ContentParent.h" @@ -21,7 +22,6 @@ #include "nsClassHashtable.h" #include "nsContentUtils.h" #include "nsError.h" -#include "nsHostObjectURI.h" #include "nsIAsyncShutdown.h" #include "nsIException.h" // for nsIStackFrame #include "nsIMemoryReporter.h" @@ -838,7 +838,7 @@ BlobURLProtocolHandler::NewURI(const nsACString& aSpec, } nsCOMPtr uri; - rv = NS_MutateURI(new nsHostObjectURI::Mutator()) + rv = NS_MutateURI(new BlobURL::Mutator()) .SetSpec(aSpec) .Apply(NS_MutatorMethod(&nsIPrincipalURIMutator::SetPrincipal, principal)) .Finalize(uri); diff --git a/dom/file/MutableBlobStorage.cpp b/dom/file/MutableBlobStorage.cpp index 3b8241b588db..2bfeae865532 100644 --- a/dom/file/MutableBlobStorage.cpp +++ b/dom/file/MutableBlobStorage.cpp @@ -4,6 +4,7 @@ * 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 "EmptyBlobImpl.h" #include "MutableBlobStorage.h" #include "MemoryBlobImpl.h" #include "mozilla/CheckedInt.h" diff --git a/dom/file/moz.build b/dom/file/moz.build index a762d762ea16..7ce10c94cc80 100644 --- a/dom/file/moz.build +++ b/dom/file/moz.build @@ -9,15 +9,12 @@ with Files("**"): DIRS += ['ipc'] -EXPORTS += [ - 'nsHostObjectURI.h', -] - EXPORTS.mozilla.dom += [ 'BaseBlobImpl.h', 'Blob.h', 'BlobImpl.h', 'BlobSet.h', + 'BlobURL.h', 'BlobURLProtocolHandler.h', 'File.h', 'FileBlobImpl.h', @@ -38,6 +35,7 @@ UNIFIED_SOURCES += [ 'Blob.cpp', 'BlobImpl.cpp', 'BlobSet.cpp', + 'BlobURL.cpp', 'BlobURLProtocolHandler.cpp', 'EmptyBlobImpl.cpp', 'File.cpp', @@ -51,7 +49,6 @@ UNIFIED_SOURCES += [ 'MultipartBlobImpl.cpp', 'MutableBlobStorage.cpp', 'MutableBlobStreamListener.cpp', - 'nsHostObjectURI.cpp', 'StreamBlobImpl.cpp', 'StringBlobImpl.cpp', 'TemporaryFileBlobImpl.cpp', diff --git a/ipc/glue/URIUtils.cpp b/ipc/glue/URIUtils.cpp index c5814424d917..726d9949a183 100644 --- a/ipc/glue/URIUtils.cpp +++ b/ipc/glue/URIUtils.cpp @@ -10,12 +10,12 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Assertions.h" +#include "mozilla/dom/BlobURL.h" #include "nsComponentManagerUtils.h" #include "nsDebug.h" #include "nsID.h" #include "nsJARURI.h" #include "nsIIconURI.h" -#include "nsHostObjectURI.h" #include "NullPrincipalURI.h" #include "nsJSProtocolHandler.h" #include "nsNetCID.h" @@ -109,7 +109,7 @@ DeserializeURI(const URIParams& aParams) break; case URIParams::THostObjectURIParams: - mutator = new nsHostObjectURI::Mutator(); + mutator = new mozilla::dom::BlobURL::Mutator(); break; default: diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index dfc94343626f..1a69bd5c7671 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -59,13 +59,13 @@ // view stuff #include "nsContentCreatorFunctions.h" -#include "nsHostObjectURI.h" #include "nsGlobalWindowCommands.h" #include "nsIControllerCommandTable.h" #include "nsJSProtocolHandler.h" #include "nsIControllerContext.h" #include "nsZipArchive.h" #include "mozilla/Attributes.h" +#include "mozilla/dom/BlobURL.h" #include "mozilla/dom/DOMRequest.h" #include "mozilla/dom/LocalStorageManager.h" #include "mozilla/dom/network/UDPSocketChild.h" @@ -196,8 +196,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(HTMLEditor) already_AddRefed NS_CreatePresentationService(); // Factory Constructor -typedef nsHostObjectURI::Mutator nsHostObjectURIMutator; -NS_GENERIC_FACTORY_CONSTRUCTOR(nsHostObjectURIMutator) +typedef mozilla::dom::BlobURL::Mutator BlobURLMutator; +NS_GENERIC_FACTORY_CONSTRUCTOR(BlobURLMutator) NS_GENERIC_FACTORY_CONSTRUCTOR(LocalStorageManager) NS_GENERIC_FACTORY_CONSTRUCTOR(SessionStorageManager) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService, @@ -787,8 +787,8 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_PLUGINDOCUMENT_CID, false, nullptr, CreatePluginDocument }, { &kNS_VIDEODOCUMENT_CID, false, nullptr, CreateVideoDocument }, { &kNS_STYLESHEETSERVICE_CID, false, nullptr, nsStyleSheetServiceConstructor }, - { &kNS_HOSTOBJECTURI_CID, false, nullptr, nsHostObjectURIMutatorConstructor }, // do_CreateInstance returns mutator - { &kNS_HOSTOBJECTURIMUTATOR_CID, false, nullptr, nsHostObjectURIMutatorConstructor }, + { &kNS_HOSTOBJECTURI_CID, false, nullptr, BlobURLMutatorConstructor }, // do_CreateInstance returns mutator + { &kNS_HOSTOBJECTURIMUTATOR_CID, false, nullptr, BlobURLMutatorConstructor }, { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, nullptr, SessionStorageManagerConstructor }, { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, nullptr, LocalStorageManagerConstructor }, { &kNS_TEXTEDITOR_CID, false, nullptr, TextEditorConstructor }, From 6b34ff8dfcee301e6bc2c83ae629702b6369cf1e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:42 +0200 Subject: [PATCH 114/116] Bug 1466023 - Get rid of GenerateURIStringForBlobURL, r=qdot --- dom/file/BlobURLProtocolHandler.cpp | 17 ++++------------- dom/file/BlobURLProtocolHandler.h | 11 ++++------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/dom/file/BlobURLProtocolHandler.cpp b/dom/file/BlobURLProtocolHandler.cpp index 57e1a88bd1ce..2cf15c92993a 100644 --- a/dom/file/BlobURLProtocolHandler.cpp +++ b/dom/file/BlobURLProtocolHandler.cpp @@ -599,7 +599,7 @@ BlobURLProtocolHandler::AddDataEntry(BlobImpl* aBlobImpl, { Init(); - nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri); + nsresult rv = GenerateURIString(aPrincipal, aUri); NS_ENSURE_SUCCESS(rv, rv); rv = AddDataEntryInternal(aUri, aBlobImpl, aPrincipal); @@ -616,7 +616,7 @@ BlobURLProtocolHandler::AddDataEntry(MediaSource* aMediaSource, { Init(); - nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri); + nsresult rv = GenerateURIString(aPrincipal, aUri); NS_ENSURE_SUCCESS(rv, rv); rv = AddDataEntryInternal(aUri, aMediaSource, aPrincipal); @@ -709,8 +709,7 @@ BlobURLProtocolHandler::HasDataEntry(const nsACString& aUri) } /* static */ nsresult -BlobURLProtocolHandler::GenerateURIString(const nsACString &aScheme, - nsIPrincipal* aPrincipal, +BlobURLProtocolHandler::GenerateURIString(nsIPrincipal* aPrincipal, nsACString& aUri) { nsresult rv; @@ -725,7 +724,7 @@ BlobURLProtocolHandler::GenerateURIString(const nsACString &aScheme, char chars[NSID_LENGTH]; id.ToProvidedString(chars); - aUri = aScheme; + aUri.AssignLiteral(BLOBURI_SCHEME); aUri.Append(':'); if (aPrincipal) { @@ -744,14 +743,6 @@ BlobURLProtocolHandler::GenerateURIString(const nsACString &aScheme, return NS_OK; } -/* static */ nsresult -BlobURLProtocolHandler::GenerateURIStringForBlobURL(nsIPrincipal* aPrincipal, - nsACString& aUri) -{ - return - GenerateURIString(NS_LITERAL_CSTRING(BLOBURI_SCHEME), aPrincipal, aUri); -} - /* static */ nsIPrincipal* BlobURLProtocolHandler::GetDataEntryPrincipal(const nsACString& aUri) { diff --git a/dom/file/BlobURLProtocolHandler.h b/dom/file/BlobURLProtocolHandler.h index 4618b5475772..2d0f5c24dced 100644 --- a/dom/file/BlobURLProtocolHandler.h +++ b/dom/file/BlobURLProtocolHandler.h @@ -40,13 +40,6 @@ public: BlobURLProtocolHandler(); - // If principal is not null, its origin will be used to generate the URI. - static nsresult GenerateURIString(const nsACString &aScheme, - nsIPrincipal* aPrincipal, - nsACString &aUri); - static nsresult GenerateURIStringForBlobURL(nsIPrincipal* aPrincipal, - nsACString &aUri); - // Methods for managing uri->object mapping // AddDataEntry creates the URI with the given scheme and returns it in aUri static nsresult AddDataEntry(mozilla::dom::BlobImpl* aBlobImpl, @@ -78,6 +71,10 @@ private: ~BlobURLProtocolHandler(); static void Init(); + + // If principal is not null, its origin will be used to generate the URI. + static nsresult GenerateURIString(nsIPrincipal* aPrincipal, + nsACString &aUri); }; bool IsBlobURI(nsIURI* aUri); From 05c0b87539d13564d2029dcfe37c3e9a17bc7f31 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Sat, 2 Jun 2018 15:51:42 +0200 Subject: [PATCH 115/116] Bug 1466023 - Move blobURL and fontTableURI code in a separate directory, r=qdot --HG-- rename : dom/file/BlobURL.cpp => dom/file/uri/BlobURL.cpp rename : dom/file/BlobURL.h => dom/file/uri/BlobURL.h rename : dom/file/BlobURLProtocolHandler.cpp => dom/file/uri/BlobURLProtocolHandler.cpp rename : dom/file/BlobURLProtocolHandler.h => dom/file/uri/BlobURLProtocolHandler.h rename : dom/file/FontTableURIProtocolHandler.cpp => dom/file/uri/FontTableURIProtocolHandler.cpp rename : dom/file/FontTableURIProtocolHandler.h => dom/file/uri/FontTableURIProtocolHandler.h --- dom/file/moz.build | 8 +----- dom/file/{ => uri}/BlobURL.cpp | 0 dom/file/{ => uri}/BlobURL.h | 0 dom/file/{ => uri}/BlobURLProtocolHandler.cpp | 0 dom/file/{ => uri}/BlobURLProtocolHandler.h | 0 .../{ => uri}/FontTableURIProtocolHandler.cpp | 0 .../{ => uri}/FontTableURIProtocolHandler.h | 0 dom/file/uri/moz.build | 28 +++++++++++++++++++ 8 files changed, 29 insertions(+), 7 deletions(-) rename dom/file/{ => uri}/BlobURL.cpp (100%) rename dom/file/{ => uri}/BlobURL.h (100%) rename dom/file/{ => uri}/BlobURLProtocolHandler.cpp (100%) rename dom/file/{ => uri}/BlobURLProtocolHandler.h (100%) rename dom/file/{ => uri}/FontTableURIProtocolHandler.cpp (100%) rename dom/file/{ => uri}/FontTableURIProtocolHandler.h (100%) create mode 100644 dom/file/uri/moz.build diff --git a/dom/file/moz.build b/dom/file/moz.build index 7ce10c94cc80..18428ce4e973 100644 --- a/dom/file/moz.build +++ b/dom/file/moz.build @@ -7,22 +7,19 @@ with Files("**"): BUG_COMPONENT = ("Core", "DOM: File") -DIRS += ['ipc'] +DIRS += ['ipc', 'uri' ] EXPORTS.mozilla.dom += [ 'BaseBlobImpl.h', 'Blob.h', 'BlobImpl.h', 'BlobSet.h', - 'BlobURL.h', - 'BlobURLProtocolHandler.h', 'File.h', 'FileBlobImpl.h', 'FileCreatorHelper.h', 'FileList.h', 'FileReader.h', 'FileReaderSync.h', - 'FontTableURIProtocolHandler.h', 'MemoryBlobImpl.h', 'MultipartBlobImpl.h', 'MutableBlobStorage.h', @@ -35,8 +32,6 @@ UNIFIED_SOURCES += [ 'Blob.cpp', 'BlobImpl.cpp', 'BlobSet.cpp', - 'BlobURL.cpp', - 'BlobURLProtocolHandler.cpp', 'EmptyBlobImpl.cpp', 'File.cpp', 'FileBlobImpl.cpp', @@ -44,7 +39,6 @@ UNIFIED_SOURCES += [ 'FileList.cpp', 'FileReader.cpp', 'FileReaderSync.cpp', - 'FontTableURIProtocolHandler.cpp', 'MemoryBlobImpl.cpp', 'MultipartBlobImpl.cpp', 'MutableBlobStorage.cpp', diff --git a/dom/file/BlobURL.cpp b/dom/file/uri/BlobURL.cpp similarity index 100% rename from dom/file/BlobURL.cpp rename to dom/file/uri/BlobURL.cpp diff --git a/dom/file/BlobURL.h b/dom/file/uri/BlobURL.h similarity index 100% rename from dom/file/BlobURL.h rename to dom/file/uri/BlobURL.h diff --git a/dom/file/BlobURLProtocolHandler.cpp b/dom/file/uri/BlobURLProtocolHandler.cpp similarity index 100% rename from dom/file/BlobURLProtocolHandler.cpp rename to dom/file/uri/BlobURLProtocolHandler.cpp diff --git a/dom/file/BlobURLProtocolHandler.h b/dom/file/uri/BlobURLProtocolHandler.h similarity index 100% rename from dom/file/BlobURLProtocolHandler.h rename to dom/file/uri/BlobURLProtocolHandler.h diff --git a/dom/file/FontTableURIProtocolHandler.cpp b/dom/file/uri/FontTableURIProtocolHandler.cpp similarity index 100% rename from dom/file/FontTableURIProtocolHandler.cpp rename to dom/file/uri/FontTableURIProtocolHandler.cpp diff --git a/dom/file/FontTableURIProtocolHandler.h b/dom/file/uri/FontTableURIProtocolHandler.h similarity index 100% rename from dom/file/FontTableURIProtocolHandler.h rename to dom/file/uri/FontTableURIProtocolHandler.h diff --git a/dom/file/uri/moz.build b/dom/file/uri/moz.build new file mode 100644 index 000000000000..b237f81a6b8f --- /dev/null +++ b/dom/file/uri/moz.build @@ -0,0 +1,28 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM: File") + +EXPORTS.mozilla.dom += [ + 'BlobURL.h', + 'BlobURLProtocolHandler.h', + 'FontTableURIProtocolHandler.h', +] + +UNIFIED_SOURCES += [ + 'BlobURL.cpp', + 'BlobURLProtocolHandler.cpp', + 'FontTableURIProtocolHandler.cpp', +] + +LOCAL_INCLUDES += [ + '/dom/file', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' From 8f2a5e19c96914f9ddc82d2409266eba0bb21270 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Sat, 2 Jun 2018 19:10:48 +0200 Subject: [PATCH 116/116] Bug 1466330 - Make nsITheme::GetWidgetBorder return the border directly instead of using an out-param (idempotent patch). r=emilio --- gfx/src/nsITheme.h | 14 ++- layout/generic/ReflowInput.cpp | 7 +- layout/generic/nsFrame.cpp | 13 +-- layout/xul/nsBox.cpp | 6 +- widget/android/nsNativeThemeAndroid.cpp | 8 +- widget/android/nsNativeThemeAndroid.h | 8 +- widget/cocoa/nsNativeThemeCocoa.h | 13 +-- widget/cocoa/nsNativeThemeCocoa.mm | 53 ++++----- widget/gtk/nsNativeThemeGTK.cpp | 45 ++++--- widget/gtk/nsNativeThemeGTK.h | 12 +- widget/headless/HeadlessThemeGTK.cpp | 89 +++++++------- widget/headless/HeadlessThemeGTK.h | 8 +- widget/windows/nsNativeThemeWin.cpp | 148 +++++++++++------------- widget/windows/nsNativeThemeWin.h | 28 ++--- 14 files changed, 218 insertions(+), 234 deletions(-) diff --git a/gfx/src/nsITheme.h b/gfx/src/nsITheme.h index 2784c2307a39..1d08da631989 100644 --- a/gfx/src/nsITheme.h +++ b/gfx/src/nsITheme.h @@ -56,6 +56,9 @@ class IpcResourceUpdateQueue; * the constants in nsThemeConstants.h). */ class nsITheme: public nsISupports { +protected: + using LayoutDeviceIntMargin = mozilla::LayoutDeviceIntMargin; + public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITHEME_IID) @@ -96,12 +99,11 @@ public: const nsRect& aRect) { return false; } /** - * Get the border for the widget, in device pixels. + * Return the border for the widget, in device pixels. */ - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, - nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) = 0; + virtual MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) = 0; /** * This method can return false to indicate that the CSS padding @@ -115,7 +117,7 @@ public: virtual bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) = 0; + LayoutDeviceIntMargin* aResult) = 0; /** * On entry, *aResult is positioned at 0,0 and sized to the new size diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index d1c7d837fa48..2e0b353069a8 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -2598,10 +2598,9 @@ SizeComputationInput::InitOffsets(WritingMode aWM, } if (isThemed) { - LayoutDeviceIntMargin border; - presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), - mFrame, disp->mAppearance, - &border); + LayoutDeviceIntMargin border = + presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), + mFrame, disp->mAppearance); ComputedPhysicalBorderPadding() = LayoutDevicePixel::ToAppUnits(border, presContext->AppUnitsPerDevPixel()); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 2462c3da7a6b..04764d865f90 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1381,10 +1381,10 @@ nsIFrame::GetUsedBorder() const const nsStyleDisplay* disp = StyleDisplay(); if (mutable_this->IsThemed(disp)) { - LayoutDeviceIntMargin widgetBorder; nsPresContext* pc = PresContext(); - pc->GetTheme()->GetWidgetBorder(pc->DeviceContext(), mutable_this, - disp->mAppearance, &widgetBorder); + LayoutDeviceIntMargin widgetBorder = + pc->GetTheme()->GetWidgetBorder(pc->DeviceContext(), mutable_this, + disp->mAppearance); border = LayoutDevicePixel::ToAppUnits(widgetBorder, pc->AppUnitsPerDevPixel()); return border; @@ -5550,10 +5550,9 @@ IntrinsicSizeOffsets(nsIFrame* aFrame, nscoord aPercentageBasis, bool aForISize) if (aFrame->IsThemed(disp)) { nsPresContext* presContext = aFrame->PresContext(); - LayoutDeviceIntMargin border; - presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), - aFrame, disp->mAppearance, - &border); + LayoutDeviceIntMargin border = + presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(), + aFrame, disp->mAppearance); result.hBorder = presContext->DevPixelsToAppUnits(verticalAxis ? border.TopBottom() : border.LeftRight()); diff --git a/layout/xul/nsBox.cpp b/layout/xul/nsBox.cpp index 90ef622274ea..d9192b2efa40 100644 --- a/layout/xul/nsBox.cpp +++ b/layout/xul/nsBox.cpp @@ -174,9 +174,9 @@ nsBox::GetXULBorder(nsMargin& aMargin) // Go to the theme for the border. nsPresContext *context = PresContext(); if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) { - LayoutDeviceIntMargin margin; - gTheme->GetWidgetBorder(context->DeviceContext(), this, - disp->mAppearance, &margin); + LayoutDeviceIntMargin margin = + gTheme->GetWidgetBorder(context->DeviceContext(), this, + disp->mAppearance); aMargin = LayoutDevicePixel::ToAppUnits(margin, context->AppUnitsPerDevPixel()); return NS_OK; diff --git a/widget/android/nsNativeThemeAndroid.cpp b/widget/android/nsNativeThemeAndroid.cpp index 6cb46f6f64ca..81702c91bfcd 100644 --- a/widget/android/nsNativeThemeAndroid.cpp +++ b/widget/android/nsNativeThemeAndroid.cpp @@ -204,13 +204,11 @@ nsNativeThemeAndroid::DrawWidgetBackground(gfxContext* aContext, return NS_OK; } -NS_IMETHODIMP +LayoutDeviceIntMargin nsNativeThemeAndroid::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + uint8_t aWidgetType) { - *aResult = LayoutDeviceIntMargin(); - return NS_OK; + return LayoutDeviceIntMargin(); } bool diff --git a/widget/android/nsNativeThemeAndroid.h b/widget/android/nsNativeThemeAndroid.h index bfc2e5230a26..682722e5ee8d 100644 --- a/widget/android/nsNativeThemeAndroid.h +++ b/widget/android/nsNativeThemeAndroid.h @@ -20,14 +20,14 @@ public: const nsRect& aRect, const nsRect& aDirtyRect) override; - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + LayoutDeviceIntMargin* aResult) override; bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame, diff --git a/widget/cocoa/nsNativeThemeCocoa.h b/widget/cocoa/nsNativeThemeCocoa.h index 239e78d524d4..8d5e63c2a24f 100644 --- a/widget/cocoa/nsNativeThemeCocoa.h +++ b/widget/cocoa/nsNativeThemeCocoa.h @@ -379,15 +379,14 @@ public: nsIFrame* aFrame, uint8_t aWidgetType, const nsRect& aRect) override; - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, - nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + LayoutDeviceIntMargin* aResult) override; virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, nsRect* aOverflowRect) override; @@ -421,8 +420,8 @@ public: protected: virtual ~nsNativeThemeCocoa(); - mozilla::LayoutDeviceIntMargin - DirectionAwareMargin(const mozilla::LayoutDeviceIntMargin& aMargin, + LayoutDeviceIntMargin + DirectionAwareMargin(const LayoutDeviceIntMargin& aMargin, nsIFrame* aFrame); nsIFrame* SeparatorResponsibility(nsIFrame* aBefore, nsIFrame* aAfter); bool IsWindowSheet(nsIFrame* aFrame); diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index 3d5ed73e44b4..655c248fd467 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -3764,30 +3764,29 @@ static const LayoutDeviceIntMargin kAquaDropdownBorder(1, 22, 2, 5); static const LayoutDeviceIntMargin kAquaComboboxBorder(3, 20, 3, 4); static const LayoutDeviceIntMargin kAquaSearchfieldBorder(3, 5, 2, 19); -NS_IMETHODIMP +LayoutDeviceIntMargin nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + uint8_t aWidgetType) { - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + LayoutDeviceIntMargin result; - aResult->SizeTo(0, 0, 0, 0); + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; switch (aWidgetType) { case NS_THEME_BUTTON: { if (IsButtonTypeMenu(aFrame)) { - *aResult = DirectionAwareMargin(kAquaDropdownBorder, aFrame); + result = DirectionAwareMargin(kAquaDropdownBorder, aFrame); } else { - *aResult = DirectionAwareMargin(LayoutDeviceIntMargin(1, 7, 3, 7), aFrame); + result = DirectionAwareMargin(LayoutDeviceIntMargin(1, 7, 3, 7), aFrame); } break; } case NS_THEME_TOOLBARBUTTON: { - *aResult = DirectionAwareMargin(LayoutDeviceIntMargin(1, 4, 1, 4), aFrame); + result = DirectionAwareMargin(LayoutDeviceIntMargin(1, 4, 1, 4), aFrame); break; } @@ -3796,17 +3795,17 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, { // nsCheckboxRadioFrame::GetIntrinsicWidth and nsCheckboxRadioFrame::GetIntrinsicHeight // assume a border width of 2px. - aResult->SizeTo(2, 2, 2, 2); + result.SizeTo(2, 2, 2, 2); break; } case NS_THEME_MENULIST: case NS_THEME_MENULIST_BUTTON: - *aResult = DirectionAwareMargin(kAquaDropdownBorder, aFrame); + result = DirectionAwareMargin(kAquaDropdownBorder, aFrame); break; case NS_THEME_MENULIST_TEXTFIELD: - *aResult = DirectionAwareMargin(kAquaComboboxBorder, aFrame); + result = DirectionAwareMargin(kAquaComboboxBorder, aFrame); break; case NS_THEME_NUMBER_INPUT: @@ -3820,23 +3819,23 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, frameOutset += textPadding; - aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset); + result.SizeTo(frameOutset, frameOutset, frameOutset, frameOutset); break; } case NS_THEME_TEXTFIELD_MULTILINE: - aResult->SizeTo(1, 1, 1, 1); + result.SizeTo(1, 1, 1, 1); break; case NS_THEME_SEARCHFIELD: - *aResult = DirectionAwareMargin(kAquaSearchfieldBorder, aFrame); + result = DirectionAwareMargin(kAquaSearchfieldBorder, aFrame); break; case NS_THEME_LISTBOX: { SInt32 frameOutset = 0; ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset); - aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset); + result.SizeTo(frameOutset, frameOutset, frameOutset, frameOutset); break; } @@ -3850,20 +3849,20 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, // scrollbar. Starting with 10.10, the expected rect for thumb // rendering is the full width of the scrollbar. if (isHorizontal) { - aResult->top = 2; - aResult->bottom = 1; + result.top = 2; + result.bottom = 1; } else { - aResult->left = 2; - aResult->right = 1; + result.left = 2; + result.right = 1; } } // Leave a bit of space at the start and the end on all OS X versions. if (isHorizontal) { - aResult->left = 1; - aResult->right = 1; + result.left = 1; + result.right = 1; } else { - aResult->top = 1; - aResult->bottom = 1; + result.top = 1; + result.bottom = 1; } } @@ -3871,17 +3870,15 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDeviceContext* aContext, } case NS_THEME_STATUSBAR: - aResult->SizeTo(1, 0, 0, 0); + result.SizeTo(1, 0, 0, 0); break; } if (IsHiDPIContext(aContext)) { - *aResult = *aResult + *aResult; // doubled + result = result + result; // doubled } - return NS_OK; - - NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(result); } // Return false here to indicate that CSS padding values should be used. There is diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp index 3c0561405355..2ee0b34d9661 100644 --- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -1275,13 +1275,12 @@ nsNativeThemeGTK::GetCachedWidgetBorder(nsIFrame* aFrame, uint8_t aWidgetType, } } -NS_IMETHODIMP +LayoutDeviceIntMargin nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + uint8_t aWidgetType) { + LayoutDeviceIntMargin result; GtkTextDirection direction = GetTextDirection(aFrame); - aResult->top = aResult->left = aResult->right = aResult->bottom = 0; switch (aWidgetType) { case NS_THEME_SCROLLBAR_HORIZONTAL: case NS_THEME_SCROLLBAR_VERTICAL: @@ -1293,10 +1292,10 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, GetActiveScrollbarMetrics(orientation); const GtkBorder& border = metrics->border.scrollbar; - aResult->top = border.top; - aResult->right = border.right; - aResult->bottom = border.bottom; - aResult->left = border.left; + result.top = border.top; + result.right = border.right; + result.bottom = border.bottom; + result.left = border.left; } break; case NS_THEME_SCROLLBARTRACK_HORIZONTAL: @@ -1309,10 +1308,10 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, GetActiveScrollbarMetrics(orientation); const GtkBorder& border = metrics->border.track; - aResult->top = border.top; - aResult->right = border.right; - aResult->bottom = border.bottom; - aResult->left = border.left; + result.top = border.top; + result.right = border.right; + result.bottom = border.bottom; + result.left = border.left; } break; case NS_THEME_TOOLBOX: @@ -1334,11 +1333,11 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, gint flags; if (!GetGtkWidgetAndState(aWidgetType, aFrame, gtkWidgetType, nullptr, - &flags)) - return NS_OK; - - moz_gtk_get_tab_border(&aResult->left, &aResult->top, - &aResult->right, &aResult->bottom, direction, + &flags)) { + return result; + } + moz_gtk_get_tab_border(&result.left, &result.top, + &result.right, &result.bottom, direction, (GtkTabFlags)flags, gtkWidgetType); } break; @@ -1353,16 +1352,16 @@ nsNativeThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, MOZ_FALLTHROUGH; default: { - GetCachedWidgetBorder(aFrame, aWidgetType, direction, aResult); + GetCachedWidgetBorder(aFrame, aWidgetType, direction, &result); } } gint scale = GetMonitorScaleFactor(aFrame); - aResult->top *= scale; - aResult->right *= scale; - aResult->bottom *= scale; - aResult->left *= scale; - return NS_OK; + result.top *= scale; + result.right *= scale; + result.bottom *= scale; + result.left *= scale; + return result; } bool diff --git a/widget/gtk/nsNativeThemeGTK.h b/widget/gtk/nsNativeThemeGTK.h index 66a4fc8ad1b5..1b5b9af6c457 100644 --- a/widget/gtk/nsNativeThemeGTK.h +++ b/widget/gtk/nsNativeThemeGTK.h @@ -38,14 +38,14 @@ public: uint8_t aWidgetType, const nsRect& aRect) override; - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + LayoutDeviceIntMargin* aResult) override; virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame, @@ -102,9 +102,9 @@ private: // corresponding entry in mBorderCache is valid. void GetCachedWidgetBorder(nsIFrame* aFrame, uint8_t aWidgetType, GtkTextDirection aDirection, - mozilla::LayoutDeviceIntMargin* aResult); + LayoutDeviceIntMargin* aResult); uint8_t mBorderCacheValid[(MOZ_GTK_WIDGET_NODE_COUNT + 7) / 8]; - mozilla::LayoutDeviceIntMargin mBorderCache[MOZ_GTK_WIDGET_NODE_COUNT]; + LayoutDeviceIntMargin mBorderCache[MOZ_GTK_WIDGET_NODE_COUNT]; }; #endif diff --git a/widget/headless/HeadlessThemeGTK.cpp b/widget/headless/HeadlessThemeGTK.cpp index f141c9ccf971..c3cb37b6536f 100644 --- a/widget/headless/HeadlessThemeGTK.cpp +++ b/widget/headless/HeadlessThemeGTK.cpp @@ -23,28 +23,27 @@ HeadlessThemeGTK::DrawWidgetBackground(gfxContext* aContext, return NS_OK; } -NS_IMETHODIMP +LayoutDeviceIntMargin HeadlessThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + uint8_t aWidgetType) { - aResult->top = aResult->right = aResult->bottom = aResult->left = 0; + LayoutDeviceIntMargin result; // The following values are generated from the Ubuntu GTK theme. switch (aWidgetType) { case NS_THEME_BUTTON: case NS_THEME_TOOLBARBUTTON: - aResult->top = 6; - aResult->right = 7; - aResult->bottom = 6; - aResult->left = 7; + result.top = 6; + result.right = 7; + result.bottom = 6; + result.left = 7; break; case NS_THEME_FOCUS_OUTLINE: case NS_THEME_NUMBER_INPUT: case NS_THEME_TEXTFIELD: - aResult->top = 5; - aResult->right = 7; - aResult->bottom = 5; - aResult->left = 7; + result.top = 5; + result.right = 7; + result.bottom = 5; + result.left = 7; break; case NS_THEME_STATUSBARPANEL: case NS_THEME_RESIZERPANEL: @@ -59,46 +58,46 @@ HeadlessThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, case NS_THEME_TEXTFIELD_MULTILINE: case NS_THEME_MENUPOPUP: case NS_THEME_GTK_INFO_BAR: - aResult->top = 1; - aResult->right = 1; - aResult->bottom = 1; - aResult->left = 1; + result.top = 1; + result.right = 1; + result.bottom = 1; + result.left = 1; break; case NS_THEME_TREEHEADERCELL: - aResult->top = 5; - aResult->right = 7; - aResult->bottom = 6; - aResult->left = 6; + result.top = 5; + result.right = 7; + result.bottom = 6; + result.left = 6; break; case NS_THEME_TAB: - aResult->top = 4; - aResult->right = 7; - aResult->bottom = 2; - aResult->left = 7; + result.top = 4; + result.right = 7; + result.bottom = 2; + result.left = 7; break; case NS_THEME_TOOLTIP: - aResult->top = 6; - aResult->right = 6; - aResult->bottom = 6; - aResult->left = 6; + result.top = 6; + result.right = 6; + result.bottom = 6; + result.left = 6; break; case NS_THEME_MENULIST: - aResult->top = 6; - aResult->right = 22; - aResult->bottom = 6; - aResult->left = 7; + result.top = 6; + result.right = 22; + result.bottom = 6; + result.left = 7; break; case NS_THEME_MENULIST_BUTTON: - aResult->top = 1; - aResult->right = 1; - aResult->bottom = 1; - aResult->left = 0; + result.top = 1; + result.right = 1; + result.bottom = 1; + result.left = 0; break; case NS_THEME_MENULIST_TEXTFIELD: - aResult->top = 1; - aResult->right = 0; - aResult->bottom = 1; - aResult->left = 1; + result.top = 1; + result.right = 0; + result.bottom = 1; + result.left = 1; break; case NS_THEME_MENUITEM: case NS_THEME_CHECKMENUITEM: @@ -106,13 +105,13 @@ HeadlessThemeGTK::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, if (IsRegularMenuItem(aFrame)) { break; } - aResult->top = 3; - aResult->right = 5; - aResult->bottom = 3; - aResult->left = 5; + result.top = 3; + result.right = 5; + result.bottom = 3; + result.left = 5; break; } - return NS_OK; + return result; } bool diff --git a/widget/headless/HeadlessThemeGTK.h b/widget/headless/HeadlessThemeGTK.h index 91770b9727c6..8097ef546cbc 100644 --- a/widget/headless/HeadlessThemeGTK.h +++ b/widget/headless/HeadlessThemeGTK.h @@ -23,14 +23,14 @@ public: const nsRect& aRect, const nsRect& aDirtyRect) override; - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + LayoutDeviceIntMargin* aResult) override; NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame, uint8_t aWidgetType, mozilla::LayoutDeviceIntSize* aResult, diff --git a/widget/windows/nsNativeThemeWin.cpp b/widget/windows/nsNativeThemeWin.cpp index 437eada736b4..280b500d60c5 100644 --- a/widget/windows/nsNativeThemeWin.cpp +++ b/widget/windows/nsNativeThemeWin.cpp @@ -610,21 +610,19 @@ nsNativeThemeWin::DrawThemedProgressMeter(nsIFrame* aFrame, int aWidgetType, } } -nsresult nsNativeThemeWin::GetCachedWidgetBorder(nsIFrame* aFrame, - HTHEME aTheme, - nsUXThemeClass aThemeClass, - uint8_t aWidgetType, - int32_t aPart, - int32_t aState, - LayoutDeviceIntMargin* aResult) +LayoutDeviceIntMargin +nsNativeThemeWin::GetCachedWidgetBorder(HTHEME aTheme, + nsUXThemeClass aThemeClass, + uint8_t aWidgetType, + int32_t aPart, + int32_t aState) { int32_t cacheIndex = aThemeClass * THEME_PART_DISTINCT_VALUE_COUNT + aPart; int32_t cacheBitIndex = cacheIndex / 8; uint8_t cacheBit = 1u << (cacheIndex % 8); if (mBorderCacheValid[cacheBitIndex] & cacheBit) { - *aResult = mBorderCache[cacheIndex]; - return NS_OK; + return mBorderCache[cacheIndex]; } // Get our info. @@ -635,20 +633,21 @@ nsresult nsNativeThemeWin::GetCachedWidgetBorder(nsIFrame* aFrame, HRESULT res = GetThemeBackgroundContentRect(aTheme, nullptr, aPart, aState, &outerRect, &contentRect); if (FAILED(res)) { - return NS_ERROR_FAILURE; + return LayoutDeviceIntMargin(); } // Now compute the delta in each direction and place it in our // nsIntMargin struct. - aResult->top = contentRect.top - outerRect.top; - aResult->bottom = outerRect.bottom - contentRect.bottom; - aResult->left = contentRect.left - outerRect.left; - aResult->right = outerRect.right - contentRect.right; + LayoutDeviceIntMargin result; + result.top = contentRect.top - outerRect.top; + result.bottom = outerRect.bottom - contentRect.bottom; + result.left = contentRect.left - outerRect.left; + result.right = outerRect.right - contentRect.right; mBorderCacheValid[cacheBitIndex] |= cacheBit; - mBorderCache[cacheIndex] = *aResult; + mBorderCache[cacheIndex] = result; - return NS_OK; + return result; } nsresult nsNativeThemeWin::GetCachedMinimumWidgetSize(nsIFrame * aFrame, HANDLE aTheme, @@ -1872,14 +1871,13 @@ RENDER_AGAIN: } else if (aWidgetType == NS_THEME_FOCUS_OUTLINE) { // Inflate 'widgetRect' with the focus outline size. - LayoutDeviceIntMargin border; - if (NS_SUCCEEDED(GetWidgetBorder(aFrame->PresContext()->DeviceContext(), - aFrame, aWidgetType, &border))) { - widgetRect.left -= border.left; - widgetRect.right += border.right; - widgetRect.top -= border.top; - widgetRect.bottom += border.bottom; - } + LayoutDeviceIntMargin border = + GetWidgetBorder(aFrame->PresContext()->DeviceContext(), + aFrame, aWidgetType); + widgetRect.left -= border.left; + widgetRect.right += border.right; + widgetRect.top -= border.top; + widgetRect.bottom += border.bottom; DTBGOPTS opts = { sizeof(DTBGOPTS), @@ -2032,26 +2030,23 @@ ScaleForFrameDPI(LayoutDeviceIntSize* aSize, nsIFrame* aFrame) } } -NS_IMETHODIMP +LayoutDeviceIntMargin nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + uint8_t aWidgetType) { + LayoutDeviceIntMargin result; mozilla::Maybe themeClass = GetThemeClass(aWidgetType); HTHEME theme = NULL; if (!themeClass.isNothing()) { theme = nsUXThemeData::GetTheme(themeClass.value()); } - nsresult rv = NS_OK; if (!theme) { - rv = ClassicGetWidgetBorder(aContext, aFrame, aWidgetType, aResult); - ScaleForFrameDPI(aResult, aFrame); - return rv; + result = ClassicGetWidgetBorder(aContext, aFrame, aWidgetType); + ScaleForFrameDPI(&result, aFrame); + return result; } - aResult->top = aResult->bottom = aResult->left = aResult->right = 0; - if (!WidgetIsContainer(aWidgetType) || aWidgetType == NS_THEME_TOOLBOX || aWidgetType == NS_THEME_WIN_MEDIA_TOOLBOX || @@ -2068,31 +2063,30 @@ nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, aWidgetType == NS_THEME_WINDOW_TITLEBAR || aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED || aWidgetType == NS_THEME_WIN_GLASS || aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS) - return NS_OK; // Don't worry about it. + return result; // Don't worry about it. int32_t part, state; - rv = GetThemePartAndState(aFrame, aWidgetType, part, state); + nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state); if (NS_FAILED(rv)) - return rv; + return result; if (aWidgetType == NS_THEME_TOOLBAR) { // make space for the separator line above all toolbars but the first if (state == 0) - aResult->top = TB_SEPARATOR_HEIGHT; - return NS_OK; + result.top = TB_SEPARATOR_HEIGHT; + return result; } - rv = GetCachedWidgetBorder(aFrame, theme, themeClass.value(), aWidgetType, part, state, aResult); - NS_ENSURE_SUCCESS(rv, rv); + result = GetCachedWidgetBorder(theme, themeClass.value(), aWidgetType, part, state); // Remove the edges for tabs that are before or after the selected tab, if (aWidgetType == NS_THEME_TAB) { if (IsLeftToSelectedTab(aFrame)) // Remove the right edge, since we won't be drawing it. - aResult->right = 0; + result.right = 0; else if (IsRightToSelectedTab(aFrame)) // Remove the left edge, since we won't be drawing it. - aResult->left = 0; + result.left = 0; } if (aFrame && (aWidgetType == NS_THEME_NUMBER_INPUT || @@ -2102,15 +2096,15 @@ nsNativeThemeWin::GetWidgetBorder(nsDeviceContext* aContext, if (content && content->IsHTMLElement()) { // We need to pad textfields by 1 pixel, since the caret will draw // flush against the edge by default if we don't. - aResult->top++; - aResult->left++; - aResult->bottom++; - aResult->right++; + result.top++; + result.left++; + result.bottom++; + result.right++; } } - ScaleForFrameDPI(aResult, aFrame); - return rv; + ScaleForFrameDPI(&result, aFrame); + return result; } bool @@ -2293,17 +2287,15 @@ nsNativeThemeWin::GetWidgetOverflow(nsDeviceContext* aContext, #endif if (aWidgetType == NS_THEME_FOCUS_OUTLINE) { - LayoutDeviceIntMargin border; - nsresult rv = GetWidgetBorder(aContext, aFrame, aWidgetType, &border); - if (NS_SUCCEEDED(rv)) { - int32_t p2a = aContext->AppUnitsPerDevPixel(); - nsMargin m(NSIntPixelsToAppUnits(border.top, p2a), - NSIntPixelsToAppUnits(border.right, p2a), - NSIntPixelsToAppUnits(border.bottom, p2a), - NSIntPixelsToAppUnits(border.left, p2a)); - aOverflowRect->Inflate(m); - return true; - } + LayoutDeviceIntMargin border = + GetWidgetBorder(aContext, aFrame, aWidgetType); + int32_t p2a = aContext->AppUnitsPerDevPixel(); + nsMargin m(NSIntPixelsToAppUnits(border.top, p2a), + NSIntPixelsToAppUnits(border.right, p2a), + NSIntPixelsToAppUnits(border.bottom, p2a), + NSIntPixelsToAppUnits(border.left, p2a)); + aOverflowRect->Inflate(m); + return true; } return false; @@ -2843,20 +2835,20 @@ nsNativeThemeWin::ClassicThemeSupportsWidget(nsIFrame* aFrame, return false; } -nsresult +LayoutDeviceIntMargin nsNativeThemeWin::ClassicGetWidgetBorder(nsDeviceContext* aContext, - nsIFrame* aFrame, - uint8_t aWidgetType, - LayoutDeviceIntMargin* aResult) + nsIFrame* aFrame, + uint8_t aWidgetType) { + LayoutDeviceIntMargin result; switch (aWidgetType) { case NS_THEME_GROUPBOX: case NS_THEME_BUTTON: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; + result.top = result.left = result.bottom = result.right = 2; break; case NS_THEME_STATUSBAR: - (*aResult).bottom = (*aResult).left = (*aResult).right = 0; - (*aResult).top = 2; + result.bottom = result.left = result.right = 0; + result.top = 2; break; case NS_THEME_LISTBOX: case NS_THEME_TREEVIEW: @@ -2867,34 +2859,34 @@ nsNativeThemeWin::ClassicGetWidgetBorder(nsDeviceContext* aContext, case NS_THEME_TEXTFIELD: case NS_THEME_TEXTFIELD_MULTILINE: case NS_THEME_FOCUS_OUTLINE: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 2; + result.top = result.left = result.bottom = result.right = 2; break; case NS_THEME_STATUSBARPANEL: case NS_THEME_RESIZERPANEL: { - (*aResult).top = 1; - (*aResult).left = 1; - (*aResult).bottom = 1; - (*aResult).right = aFrame->GetNextSibling() ? 3 : 1; + result.top = 1; + result.left = 1; + result.bottom = 1; + result.right = aFrame->GetNextSibling() ? 3 : 1; break; - } + } case NS_THEME_TOOLTIP: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; + result.top = result.left = result.bottom = result.right = 1; break; case NS_THEME_PROGRESSBAR: case NS_THEME_PROGRESSBAR_VERTICAL: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 1; + result.top = result.left = result.bottom = result.right = 1; break; case NS_THEME_MENUBAR: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 0; + result.top = result.left = result.bottom = result.right = 0; break; case NS_THEME_MENUPOPUP: - (*aResult).top = (*aResult).left = (*aResult).bottom = (*aResult).right = 3; + result.top = result.left = result.bottom = result.right = 3; break; default: - (*aResult).top = (*aResult).bottom = (*aResult).left = (*aResult).right = 0; + result.top = result.bottom = result.left = result.right = 0; break; } - return NS_OK; + return result; } bool diff --git a/widget/windows/nsNativeThemeWin.h b/widget/windows/nsNativeThemeWin.h index 9cac2031e0ae..88016242ed89 100644 --- a/widget/windows/nsNativeThemeWin.h +++ b/widget/windows/nsNativeThemeWin.h @@ -40,15 +40,14 @@ public: nscolor GetWidgetAutoColor(mozilla::ComputedStyle* aStyle, uint8_t aWidgetType) override; - NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, - nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + MOZ_MUST_USE LayoutDeviceIntMargin GetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType) override; bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult) override; + LayoutDeviceIntMargin* aResult) override; virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame, @@ -100,14 +99,13 @@ protected: uint8_t aWidgetType, const nsRect& aRect, const nsRect& aClipRect); - nsresult ClassicGetWidgetBorder(nsDeviceContext* aContext, - nsIFrame* aFrame, - uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult); + MOZ_MUST_USE LayoutDeviceIntMargin ClassicGetWidgetBorder(nsDeviceContext* aContext, + nsIFrame* aFrame, + uint8_t aWidgetType); bool ClassicGetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - mozilla::LayoutDeviceIntMargin* aResult); + LayoutDeviceIntMargin* aResult); nsresult ClassicGetMinimumWidgetSize(nsIFrame* aFrame, uint8_t aWidgetType, mozilla::LayoutDeviceIntSize* aResult, bool* aIsOverridable); @@ -131,9 +129,11 @@ protected: int aPart, int aState, RECT* aWidgetRect, RECT* aClipRect); - nsresult GetCachedWidgetBorder(nsIFrame* aFrame, HANDLE aTheme, nsUXThemeClass aThemeClass, - uint8_t aWidgetType, int32_t aPart, int32_t aState, - mozilla::LayoutDeviceIntMargin* aResult); + MOZ_MUST_USE LayoutDeviceIntMargin GetCachedWidgetBorder(HANDLE aTheme, + nsUXThemeClass aThemeClass, + uint8_t aWidgetType, + int32_t aPart, + int32_t aState); nsresult GetCachedMinimumWidgetSize(nsIFrame* aFrame, HANDLE aTheme, nsUXThemeClass aThemeClass, uint8_t aWidgetType, int32_t aPart, int32_t aState, @@ -151,7 +151,7 @@ private: // the aWidgetType value instead, but there would be some uncacheable values, since // we derive some theme parts from other arguments. uint8_t mBorderCacheValid[(eUXNumClasses * THEME_PART_DISTINCT_VALUE_COUNT + 7) / 8]; - mozilla::LayoutDeviceIntMargin mBorderCache[eUXNumClasses * THEME_PART_DISTINCT_VALUE_COUNT]; + LayoutDeviceIntMargin mBorderCache[eUXNumClasses * THEME_PART_DISTINCT_VALUE_COUNT]; // See the above not for mBorderCache and friends. However mozilla::LayoutDeviceIntSize // is half the size of nsIntMargin, making the cache roughly half as large. In total