Merge mozilla-central to mozilla-inbound. r=merge a=merge CLOSED TREE

This commit is contained in:
Gurzau Raul 2017-12-09 00:57:59 +02:00
Родитель 5e595aa93a 91d3bc0100
Коммит 0fcc1a37e6
1016 изменённых файлов: 18636 добавлений и 98452 удалений

Просмотреть файл

@ -220,6 +220,7 @@ dom/fetch/**
dom/file/**
dom/filehandle/**
dom/filesystem/**
dom/flex/**
dom/flyweb/**
dom/gamepad/**
dom/geolocation/**

Просмотреть файл

@ -54,7 +54,7 @@ if CONFIG['MOZ_ENABLE_DBUS']:
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
# Used in G_DEFINE_TYPE_EXTENDED macro, probably fixed in newer glib /
# gobject headers. See bug 1243331 comment 3.
CXXFLAGS += [

Просмотреть файл

@ -112,5 +112,5 @@ FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -29,7 +29,6 @@
#include "nsIDOMXULDocument.h"
#include "nsIDOMMutationEvent.h"
#include "nsPIDOMWindow.h"
#include "nsIDOMXULPopupElement.h"
#include "nsIEditingSession.h"
#include "nsIFrame.h"
#include "nsIInterfaceRequestorUtils.h"

Просмотреть файл

@ -66,5 +66,5 @@ FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -46,5 +46,5 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -25,5 +25,5 @@ FINAL_LIBRARY = 'xul'
# #endif !_MIDL_USE_GUIDDEF_
#
# which clang-cl complains about. MSVC doesn't, so turn this warning off.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CFLAGS += ['-Wno-extra-tokens']

Просмотреть файл

@ -91,5 +91,5 @@ RCINCLUDE = 'IA2Marshal.rc'
# #endif !_MIDL_USE_GUIDDEF_
#
# which clang-cl complains about. MSVC doesn't, so turn this warning off.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CXXFLAGS += ['-Wno-extra-tokens']

Просмотреть файл

@ -41,5 +41,5 @@ RCINCLUDE = 'AccessibleMarshal.rc'
# #endif !_MIDL_USE_GUIDDEF_
#
# which clang-cl complains about. MSVC doesn't, so turn this warning off.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CFLAGS += ['-Wno-extra-tokens']

Просмотреть файл

@ -33,7 +33,7 @@ EXPORTS.mozilla.a11y += [
'IPCTypes.h',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
if CONFIG['ACCESSIBILITY']:

Просмотреть файл

@ -40,7 +40,7 @@ if CONFIG['ACCESSIBILITY']:
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -23,5 +23,5 @@ LOCAL_INCLUDES += [
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -5,3 +5,4 @@ support-files =
!/accessible/tests/mochitest/*.js
[browser_test_doc_creation.js]
[browser_test_urlbar.js]

Просмотреть файл

@ -4,18 +4,6 @@
"use strict";
const nsIAccessibleRole = Ci.nsIAccessibleRole; // eslint-disable-line no-unused-vars
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
async function openNewTab(url) {
const forceNewProcess = true;
return BrowserTestUtils.openNewForegroundTab(
{ gBrowser, url, forceNewProcess });
}
const tab1URL = `data:text/html,
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

Просмотреть файл

@ -0,0 +1,34 @@
/* 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";
// Checking that the awesomebar popup gets COMBOBOX_LIST role instead of
// LISTBOX, since its parent is a <panel> (see Bug 1422465)
add_task(async function testAutocompleteRichResult() {
let tab = await openNewTab("data:text/html;charset=utf-8,");
let accService = await initAccessibilityService();
info("Opening the URL bar and entering a key to show the PopupAutoCompleteRichResult panel");
let urlbar = document.getElementById("urlbar");
urlbar.focus();
let urlbarPopup = document.getElementById("PopupAutoCompleteRichResult");
let shown = BrowserTestUtils.waitForEvent(urlbarPopup, "popupshown");
EventUtils.synthesizeKey("a", {});
await shown;
info("Waiting for accessibility to be created for the richlistbox");
let richlistbox = document.getAnonymousElementByAttribute(urlbarPopup, "anonid", "richlistbox");
await BrowserTestUtils.waitForCondition(() => accService.getAccessibleFor(richlistbox));
info("Confirming that the special case is handled in XULListboxAccessible");
let accessible = accService.getAccessibleFor(richlistbox);
is(accessible.role, ROLE_COMBOBOX_LIST, "Right role");
await BrowserTestUtils.removeTab(tab);
});
registerCleanupFunction(async function() {
await shutdownAccessibilityService();
});

Просмотреть файл

@ -4,7 +4,7 @@
"use strict";
/* exported initAccessibilityService, shutdownAccessibilityService */
/* exported initAccessibilityService, openNewTab, shutdownAccessibilityService */
// Load the shared-head file first.
/* import-globals-from ../shared-head.js */
@ -12,6 +12,18 @@ Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
this);
const nsIAccessibleRole = Ci.nsIAccessibleRole; // eslint-disable-line no-unused-vars
/* import-globals-from ../../mochitest/role.js */
loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
async function openNewTab(url) {
const forceNewProcess = true;
return BrowserTestUtils.openNewForegroundTab(
{ gBrowser, url, forceNewProcess });
}
async function initAccessibilityService() {
info("Create accessibility service.");
let accService = Cc["@mozilla.org/accessibilityService;1"].getService(

Просмотреть файл

@ -52,7 +52,7 @@ FINAL_LIBRARY = 'xul'
# #endif !_MIDL_USE_GUIDDEF_
#
# which clang-cl complains about. MSVC doesn't, so turn this warning off.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CXXFLAGS += ['-Wno-extra-tokens']
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -74,7 +74,7 @@ LOCAL_INCLUDES += [
# #endif !_MIDL_USE_GUIDDEF_
#
# which clang-cl complains about. MSVC doesn't, so turn this warning off.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CXXFLAGS += ['-Wno-extra-tokens']
include('/ipc/chromium/chromium-config.mozbuild')

Просмотреть файл

@ -62,5 +62,5 @@ FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -18,7 +18,6 @@
#include "nsIDOMXULMenuListElement.h"
#include "nsIDOMXULMultSelectCntrlEl.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMXULPopupElement.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
#include "nsIMutableArray.h"
#include "nsIPersistentProperties2.h"
@ -157,9 +156,7 @@ XULListboxAccessible::NativeRole()
{
// A richlistbox is used with the new autocomplete URL bar, and has a parent
// popup <panel>.
nsCOMPtr<nsIDOMXULPopupElement> xulPopup =
do_QueryInterface(mContent->GetParent());
if (xulPopup)
if (mContent->GetParent()->IsXULElement(nsGkAtoms::panel))
return roles::COMBOBOX_LIST;
return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;

Просмотреть файл

@ -53,5 +53,5 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -62,7 +62,7 @@ if CONFIG['LIBFUZZER']:
if CONFIG['ENABLE_GECKODRIVER']:
DEFINES['MOZ_GECKODRIVER'] = True
if CONFIG['_MSC_VER']:
if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
# Always enter a Windows program through wmain, whether or not we're
# a console application.
WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
@ -95,7 +95,7 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
# The heap will grow if need be.
#
# Set it to 256k. See bug 127069.
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['CC_TYPE'] not in ('clang', 'gcc'):
LDFLAGS += ['/HEAP:0x40000']
DisableStlWrapping()

Просмотреть файл

@ -43,13 +43,10 @@ pref("extensions.webextOptionalPermissionPrompts", true);
// Preferences for AMO integration
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%");
pref("extensions.getAddons.getWithPerformance.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/guid:%IDS%?src=firefox&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%&platform=%OS%&appver=%VERSION%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/firefox/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%?src=firefox");
pref("extensions.webservice.discoverURL", "https://discovery.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");
pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/list/recommended/all/%MAX_RESULTS%/%OS%/%VERSION%?src=firefox");
pref("extensions.getAddons.link.url", "https://addons.mozilla.org/%LOCALE%/firefox/");
pref("extensions.getAddons.themes.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes/?src=firefox");
@ -396,9 +393,9 @@ pref("browser.search.geoSpecificDefaults", false);
pref("browser.search.geoSpecificDefaults.url", "https://search.services.mozilla.com/1/%APP%/%VERSION%/%CHANNEL%/%LOCALE%/%REGION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%");
// US specific default (used as a fallback if the geoSpecificDefaults request fails).
pref("browser.search.defaultenginename.US", "data:text/plain,browser.search.defaultenginename.US=Yahoo");
pref("browser.search.order.US.1", "data:text/plain,browser.search.order.US.1=Yahoo");
pref("browser.search.order.US.2", "data:text/plain,browser.search.order.US.2=Google");
pref("browser.search.defaultenginename.US", "data:text/plain,browser.search.defaultenginename.US=Google");
pref("browser.search.order.US.1", "data:text/plain,browser.search.order.US.1=Google");
pref("browser.search.order.US.2", "data:text/plain,browser.search.order.US.2=Yahoo");
pref("browser.search.order.US.3", "data:text/plain,browser.search.order.US.3=Bing");
// search bar results always open in a new tab

Просмотреть файл

@ -16,12 +16,10 @@ support-files =
browser_webext_update_origins1.xpi
browser_webext_update_origins2.xpi
browser_webext_update.json
browser_webext_search.xml
[browser_extension_sideloading.js]
[browser_extension_update_background.js]
[browser_extension_update_background_noprompt.js]
[browser_permissions_addons_search.js]
[browser_permissions_installTrigger.js]
[browser_permissions_local_file.js]
[browser_permissions_mozAddonManager.js]

Просмотреть файл

@ -1,42 +0,0 @@
"use strict";
async function installSearch(filename) {
await SpecialPowers.pushPrefEnv({set: [
["extensions.getAddons.maxResults", 10],
["extensions.getAddons.search.url", `${BASE}/browser_webext_search.xml`],
]});
let win = await BrowserOpenAddonsMgr("addons://list/extension");
let searchResultsPromise = new Promise(resolve => {
win.document.addEventListener("ViewChanged", resolve, {once: true});
});
let search = win.document.getElementById("header-search");
search.focus();
search.value = "search text";
EventUtils.synthesizeKey("VK_RETURN", {}, win);
await searchResultsPromise;
ok(win.gViewController.currentViewId.startsWith("addons://search"),
"about:addons is displaying search results");
let list = win.document.getElementById("search-list");
let item = null;
for (let child of list.childNodes) {
if (child.nodeName == "richlistitem" &&
child.mAddon.install.sourceURI.pathQueryRef.endsWith(filename)) {
item = child;
break;
}
}
ok(item, `Found ${filename} in search results`);
// abracadabara XBL
item.clientTop;
let install = win.document.getAnonymousElementByAttribute(item, "anonid", "install-status");
let button = win.document.getAnonymousElementByAttribute(install, "anonid", "install-remote-btn");
EventUtils.synthesizeMouseAtCenter(button, {}, win);
}
add_task(() => testInstallMethod(installSearch, "installAmo"));

Просмотреть файл

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<searchresults total_results="2">
<addon>
<name>permissions test</name>
<type id='1'>Extension</type>
<guid>permissions@tests.mozilla.org</guid>
<version>1.1</version>
<authors>
<author>
<name>Test Creator</name>
<link>http://example.com/creator.html</link>
</author>
</authors>
<status id='4'>Public</status>
<compatible_applications>
<application>
<name>Firefox</name>
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
<min_version>0</min_version>
<max_version>*</max_version>
</application>
</compatible_applications>
<compatible_os>ALL</compatible_os>
<install size="1">https://example.com/browser/browser/base/content/test/webextensions/browser_webext_permissions.xpi</install>
</addon>
<addon>
<name>no permissions</name>
<type id='1'>Extension</type>
<guid>nopermissions@tests.mozilla.org</guid>
<version>1.0</version>
<authors>
<author>
<name>Test Creator</name>
<link>http://example.com/creator.html</link>
</author>
</authors>
<status id='4'>Public</status>
<compatible_applications>
<application>
<name>Firefox</name>
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
<min_version>0</min_version>
<max_version>*</max_version>
</application>
</compatible_applications>
<compatible_os>ALL</compatible_os>
<install size="1">https://example.com/browser/browser/base/content/test/webextensions/browser_webext_nopermissions.xpi</install>
</addon>
</searchresults>

Просмотреть файл

@ -6,6 +6,8 @@
BROWSER_CHROME_MANIFESTS += [
'test/browser.ini',
'test/google_codes/browser.ini',
'test/google_nocodes/browser.ini',
]
JAR_MANIFESTS += ['jar.mn']

Просмотреть файл

@ -27,10 +27,6 @@ skip-if = os == "mac" # bug 967013
skip-if = artifact # bug 1315953
[browser_google.js]
skip-if = artifact # bug 1315953
[browser_google_codes.js]
skip-if = artifact # bug 1315953
[browser_google_nocodes.js]
skip-if = artifact # bug 1315953
[browser_google_behavior.js]
skip-if = artifact # bug 1315953
[browser_healthreport.js]

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -9,7 +9,7 @@
"use strict";
const SEARCH_ENGINE_DETAILS = [{
let searchEngineDetails = [{
alias: "g",
baseURL: "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8",
codes: {
@ -21,6 +21,29 @@ const SEARCH_ENGINE_DETAILS = [{
name: "Google",
}];
let countryCode = Services.prefs.getCharPref("browser.search.countryCode");
let code = "";
switch (countryCode) {
case "US":
code = "firefox-b-1";
break;
case "DE":
code = "firefox-b";
break;
case "RU":
// Covered by test but doesn't use a code
break;
}
if (code) {
let codes = searchEngineDetails[0].codes;
let suffix = `&client=${code}`;
codes.context = suffix;
codes.newTab = suffix;
codes.submission = suffix;
codes.keyword = `${suffix}-ab`;
}
function promiseStateChangeURI() {
return new Promise(resolve => {
let listener = {
@ -74,7 +97,7 @@ function promiseContentSearchReady(browser) {
});
}
for (let engine of SEARCH_ENGINE_DETAILS) {
for (let engine of searchEngineDetails) {
add_task(async function() {
let previouslySelectedEngine = Services.search.currentEngine;

Просмотреть файл

@ -1,165 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const kUrlPref = "geoSpecificDefaults.url";
const BROWSER_SEARCH_PREF = "browser.search.";
var originalGeoURL;
var originalCountryCode;
var originalRegion;
/**
* Clean the profile of any cache file left from a previous run.
* Returns a boolean indicating if the cache file existed.
*/
function removeCacheFile() {
const CACHE_FILENAME = "search.json.mozlz4";
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
file.append(CACHE_FILENAME);
if (file.exists()) {
file.remove(false);
return true;
}
return false;
}
/**
* Returns a promise that is resolved when an observer notification from the
* search service fires with the specified data.
*
* @param aExpectedData
* The value the observer notification sends that causes us to resolve
* the promise.
*/
function waitForSearchNotification(aExpectedData, aCallback) {
const SEARCH_SERVICE_TOPIC = "browser-search-service";
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
if (aData != aExpectedData)
return;
Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
aCallback();
}, SEARCH_SERVICE_TOPIC);
}
function asyncInit() {
return new Promise(resolve => {
Services.search.init(function() {
ok(Services.search.isInitialized, "search service should be initialized");
resolve();
});
});
}
function asyncReInit() {
let promise = new Promise(resolve => {
waitForSearchNotification("reinit-complete", resolve);
});
Services.search.QueryInterface(Ci.nsIObserver)
.observe(null, "intl:requested-locales-changed", null);
return promise;
}
let gEngineCount;
add_task(async function preparation() {
// ContentSearch is interferring with our async re-initializations of the
// search service: once _initServicePromise has resolved, it will access
// the search service, thus causing unpredictable behavior due to
// synchronous initializations of the service.
let originalContentSearchPromise = ContentSearch._initServicePromise;
ContentSearch._initServicePromise = new Promise(resolve => {
registerCleanupFunction(() => {
ContentSearch._initServicePromise = originalContentSearchPromise;
resolve();
});
});
await asyncInit();
gEngineCount = Services.search.getVisibleEngines().length;
waitForSearchNotification("uninit-complete", () => {
// Verify search service is not initialized
is(Services.search.isInitialized, false, "Search service should NOT be initialized");
removeCacheFile();
// Make sure we get the new country/region values, but save the old
originalCountryCode = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "countryCode");
originalRegion = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "region");
Services.prefs.clearUserPref(BROWSER_SEARCH_PREF + "countryCode");
Services.prefs.clearUserPref(BROWSER_SEARCH_PREF + "region");
// Geo specific defaults won't be fetched if there's no country code.
Services.prefs.setCharPref("browser.search.geoip.url",
'data:application/json,{"country_code": "DE"}');
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
// Avoid going to the server for the geo lookup. We take the defaults
originalGeoURL = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + kUrlPref);
let geoUrl = "data:application/json,{}";
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, geoUrl);
});
await asyncReInit();
await new Promise(resolve => {
waitForSearchNotification("write-cache-to-disk-complete", resolve);
});
});
add_task(async function tests() {
let engine = Services.search.getEngineByName("Google");
ok(engine, "Google");
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8&client=firefox-b";
// Keyword uses a slightly different code
let keywordBase = base + "-ab";
let url;
// Test search URLs (including purposes).
url = engine.getSubmission("foo", null, "contextmenu").uri.spec;
is(url, base, "Check context menu search URL for 'foo'");
url = engine.getSubmission("foo", null, "keyword").uri.spec;
is(url, keywordBase, "Check keyword search URL for 'foo'");
url = engine.getSubmission("foo", null, "searchbar").uri.spec;
is(url, base, "Check search bar search URL for 'foo'");
url = engine.getSubmission("foo", null, "homepage").uri.spec;
is(url, base, "Check homepage search URL for 'foo'");
url = engine.getSubmission("foo", null, "newtab").uri.spec;
is(url, base, "Check newtab search URL for 'foo'");
url = engine.getSubmission("foo", null, "system").uri.spec;
is(url, base, "Check system search URL for 'foo'");
});
add_task(async function cleanup() {
waitForSearchNotification("uninit-complete", () => {
// Verify search service is not initialized
is(Services.search.isInitialized, false,
"Search service should NOT be initialized");
removeCacheFile();
Services.prefs.clearUserPref("browser.search.geoip.url");
Services.prefs.setCharPref(BROWSER_SEARCH_PREF + "countryCode", originalCountryCode);
Services.prefs.setCharPref(BROWSER_SEARCH_PREF + "region", originalRegion);
// We can't clear the pref because it's set to false by testing/profiles/prefs_general.js
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", false);
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, originalGeoURL);
});
await asyncReInit();
is(gEngineCount, Services.search.getVisibleEngines().length,
"correct engine count after cleanup");
});

Просмотреть файл

@ -1,162 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const kUrlPref = "geoSpecificDefaults.url";
const BROWSER_SEARCH_PREF = "browser.search.";
var originalGeoURL;
var originalCountryCode;
var originalRegion;
/**
* Clean the profile of any cache file left from a previous run.
* Returns a boolean indicating if the cache file existed.
*/
function removeCacheFile() {
const CACHE_FILENAME = "search.json.mozlz4";
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
file.append(CACHE_FILENAME);
if (file.exists()) {
file.remove(false);
return true;
}
return false;
}
/**
* Returns a promise that is resolved when an observer notification from the
* search service fires with the specified data.
*
* @param aExpectedData
* The value the observer notification sends that causes us to resolve
* the promise.
*/
function waitForSearchNotification(aExpectedData, aCallback) {
const SEARCH_SERVICE_TOPIC = "browser-search-service";
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
if (aData != aExpectedData)
return;
Services.obs.removeObserver(observer, SEARCH_SERVICE_TOPIC);
aCallback();
}, SEARCH_SERVICE_TOPIC);
}
function asyncInit() {
return new Promise(resolve => {
Services.search.init(function() {
ok(Services.search.isInitialized, "search service should be initialized");
resolve();
});
});
}
function asyncReInit() {
let promise = new Promise(resolve => {
waitForSearchNotification("reinit-complete", resolve);
});
Services.search.QueryInterface(Ci.nsIObserver)
.observe(null, "intl:requested-locales-changed", null);
return promise;
}
let gEngineCount;
add_task(async function preparation() {
// ContentSearch is interferring with our async re-initializations of the
// search service: once _initServicePromise has resolved, it will access
// the search service, thus causing unpredictable behavior due to
// synchronous initializations of the service.
let originalContentSearchPromise = ContentSearch._initServicePromise;
ContentSearch._initServicePromise = new Promise(resolve => {
registerCleanupFunction(() => {
ContentSearch._initServicePromise = originalContentSearchPromise;
resolve();
});
});
await asyncInit();
gEngineCount = Services.search.getVisibleEngines().length;
waitForSearchNotification("uninit-complete", () => {
// Verify search service is not initialized
is(Services.search.isInitialized, false, "Search service should NOT be initialized");
removeCacheFile();
// Make sure we get the new country/region values, but save the old
originalCountryCode = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "countryCode");
originalRegion = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + "region");
Services.prefs.clearUserPref(BROWSER_SEARCH_PREF + "countryCode");
Services.prefs.clearUserPref(BROWSER_SEARCH_PREF + "region");
// Geo specific defaults won't be fetched if there's no country code.
Services.prefs.setCharPref("browser.search.geoip.url",
'data:application/json,{"country_code": "US"}');
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", true);
// Avoid going to the server for the geo lookup. We take the defaults
originalGeoURL = Services.prefs.getCharPref(BROWSER_SEARCH_PREF + kUrlPref);
let geoUrl = "data:application/json,{}";
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, geoUrl);
});
await asyncReInit();
await new Promise(resolve => {
waitForSearchNotification("write-cache-to-disk-complete", resolve);
});
});
add_task(async function tests() {
let engine = Services.search.getEngineByName("Google");
ok(engine, "Google");
let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8";
let url;
// Test search URLs (including purposes).
url = engine.getSubmission("foo", null, "contextmenu").uri.spec;
is(url, base, "Check context menu search URL for 'foo'");
url = engine.getSubmission("foo", null, "keyword").uri.spec;
is(url, base, "Check keyword search URL for 'foo'");
url = engine.getSubmission("foo", null, "searchbar").uri.spec;
is(url, base, "Check search bar search URL for 'foo'");
url = engine.getSubmission("foo", null, "homepage").uri.spec;
is(url, base, "Check homepage search URL for 'foo'");
url = engine.getSubmission("foo", null, "newtab").uri.spec;
is(url, base, "Check newtab search URL for 'foo'");
url = engine.getSubmission("foo", null, "system").uri.spec;
is(url, base, "Check system search URL for 'foo'");
});
add_task(async function cleanup() {
waitForSearchNotification("uninit-complete", () => {
// Verify search service is not initialized
is(Services.search.isInitialized, false,
"Search service should NOT be initialized");
removeCacheFile();
Services.prefs.clearUserPref("browser.search.geoip.url");
Services.prefs.setCharPref(BROWSER_SEARCH_PREF + "countryCode", originalCountryCode);
Services.prefs.setCharPref(BROWSER_SEARCH_PREF + "region", originalRegion);
// We can't clear the pref because it's set to false by testing/profiles/prefs_general.js
Services.prefs.setBoolPref("browser.search.geoSpecificDefaults", false);
Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF).setCharPref(kUrlPref, originalGeoURL);
});
await asyncReInit();
is(gEngineCount, Services.search.getVisibleEngines().length,
"correct engine count after cleanup");
});

Просмотреть файл

@ -0,0 +1,8 @@
[DEFAULT]
prefs =
browser.search.countryCode='DE'
[../browser_google.js]
skip-if = artifact # bug 1315953
[../browser_google_behavior.js]
skip-if = artifact # bug 1315953

Просмотреть файл

@ -0,0 +1,8 @@
[DEFAULT]
prefs =
browser.search.countryCode='RU'
[../browser_google.js]
skip-if = artifact # bug 1315953
[../browser_google_behavior.js]
skip-if = artifact # bug 1315953

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -2,7 +2,6 @@
# safeguard below
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -2,7 +2,6 @@
# safeguard below
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -2,7 +2,6 @@
# safeguard below
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -42,7 +42,6 @@ for platform in all_platforms:
'ac_add_options --enable-official-branding',
'export BUILDING_RELEASE=1',
'if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then',
'MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}',
'MOZ_AUTOMATION_UPDATE_PACKAGING=1',
'fi',
]

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -8,10 +8,6 @@
# MinGW does not have (or need) makecab
unset MAKECAB
# These aren't supported on mingw at this time
# Bug 1393817
MOZ_AUTOMATION_L10N_CHECK=0
# Sets:
# build/mozconfig.common
# AUTOCLOBBER=1

Просмотреть файл

@ -2,7 +2,6 @@
# safeguard below
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -1,5 +1,4 @@
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -2,7 +2,6 @@
# safeguard below
if [ -n "$ENABLE_RELEASE_PROMOTION" ]; then
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=1
fi

Просмотреть файл

@ -6,10 +6,9 @@
},
"regionOverrides": {
"US": {
"google": "google-nocodes"
"google": "google-2018"
},
"CA": {
"google": "google-nocodes",
"ebay": "ebay-ca",
"ebay-fr": "ebay-ca"
},
@ -28,12 +27,6 @@
"CN": {
"google": "google-nocodes"
},
"TW": {
"google": "google-nocodes"
},
"HK": {
"google": "google-nocodes"
},
"AT": {
"ebay-de": "ebay-at"
},

Просмотреть файл

@ -41,7 +41,7 @@ def GeckoBinary(linkage='dependent', mozglue=None):
if mozglue == 'program':
USE_LIBS += ['mozglue']
DEFINES['MOZ_HAS_MOZGLUE'] = True
if CONFIG['MOZ_GLUE_IN_PROGRAM'] and CONFIG['GNU_CC']:
if CONFIG['MOZ_GLUE_IN_PROGRAM'] and CONFIG['CC_TYPE'] in ('clang', 'gcc'):
LDFLAGS += ['-rdynamic']
elif mozglue == 'library':
LIBRARY_DEFINES['MOZ_HAS_MOZGLUE'] = True

Просмотреть файл

@ -24,7 +24,7 @@ gyp_vars.update({
'include_pulse_audio': 1 if CONFIG['MOZ_PULSEAUDIO'] else 0,
# basic stuff for everything
'include_internal_video_render': 0,
'clang': 1 if CONFIG['CLANG_CXX'] else 0,
'clang': 1 if CONFIG['CC_TYPE'] == 'clang' else 0,
'clang_use_chrome_plugins': 0,
'enable_protobuf': 0,
'include_tests': 0,

Просмотреть файл

@ -4,7 +4,6 @@
if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
fi
. "$topsrcdir/build/mozconfig.common"

Просмотреть файл

@ -46,7 +46,7 @@ FINAL_TARGET_PP_FILES += ['.gdbinit_python.in']
OBJDIR_FILES += ['!/dist/bin/.gdbinit_python']
# Install the clang-cl runtime library for ASAN next to the binaries we produce.
if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']:
if CONFIG['MOZ_ASAN'] and CONFIG['CC_TYPE'] == 'clang-cl':
FINAL_TARGET_FILES += ['%' + CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
if CONFIG['LLVM_SYMBOLIZER']:

Просмотреть файл

@ -66,7 +66,7 @@ def rust_compiler(rustc_info, cargo_info):
You can install rust by running './mach bootstrap'
or by directly running the installer from https://rustup.rs/
'''))
rustc_min_version = Version('1.21.0')
rustc_min_version = Version('1.22.1')
cargo_min_version = Version('0.{}'.format(rustc_min_version.minor + 1))
version = rustc_info.version

Просмотреть файл

@ -17,6 +17,5 @@ mk_add_options "export MOZ_AUTOMATION_INSTALLER=${MOZ_AUTOMATION_INSTALLER-0}"
mk_add_options "export MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-0}"
mk_add_options "export MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=${MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES-1}"
mk_add_options "export MOZ_AUTOMATION_UPLOAD=${MOZ_AUTOMATION_UPLOAD-1}"
mk_add_options "export MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-0}"
export MOZ_AUTOMATION_MOZCONFIG=1

Просмотреть файл

@ -4,7 +4,6 @@
if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
fi

Просмотреть файл

@ -0,0 +1,4 @@
%include build/sparse-profiles/mach
[include]
path:toolkit/crashreporter/tools/upload_symbols.py

Просмотреть файл

@ -1,6 +1,5 @@
if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
fi

Просмотреть файл

@ -49,6 +49,8 @@ const URLs = new Map([
["http://www.example2.com", true, true, true],
["feed:http://www.example2.com", false, false, true],
["https://www.example2.com", true, true, true],
["moz-icon:file:///foo/bar/baz.exe", false, false, true],
["moz-icon://.exe", false, false, true],
["chrome://foo/content/bar.xul", false, false, true],
["feed:chrome://foo/content/bar.xul", false, false, false],
["view-source:http://www.example2.com", false, false, true],
@ -70,6 +72,8 @@ const URLs = new Map([
["http://www.example2.com", true, true, true],
["feed:http://www.example2.com", true, true, true],
["https://www.example2.com", true, true, true],
["moz-icon:file:///foo/bar/baz.exe", false, false, true],
["moz-icon://.exe", false, false, true],
["feed:https://www.example2.com", true, true, true],
["chrome://foo/content/bar.xul", false, false, true],
["feed:chrome://foo/content/bar.xul", false, false, false],
@ -92,6 +96,8 @@ const URLs = new Map([
["http://www.example2.com", true, true, true],
["feed:http://www.example2.com", false, false, true],
["https://www.example2.com", true, true, true],
["moz-icon:file:///foo/bar/baz.exe", false, false, true],
["moz-icon://.exe", false, false, true],
["feed:https://www.example2.com", false, false, true],
["chrome://foo/content/bar.xul", false, false, true],
["feed:chrome://foo/content/bar.xul", false, false, false],
@ -128,6 +134,8 @@ const URLs = new Map([
["about:test-content-linkable", true, true, true],
["about:test-unknown-linkable", true, true, true],
["moz-icon:file:///foo/bar/baz.exe", true, true, true],
["moz-icon://.exe", true, true, true],
]],
["about:test-unknown-unlinkable", [
["about:test-chrome-privs", false, false, true],

4
config/external/ffi/moz.build поставляемый
Просмотреть файл

@ -60,7 +60,7 @@ else:
else:
DEFINES['EH_FRAME_FLAGS'] = '"a"'
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
ASFLAGS += ['-clang-cl']
# Common source files.
@ -76,7 +76,7 @@ else:
ffi_srcs = ()
if CONFIG['FFI_TARGET'] == 'ARM':
ffi_srcs = ('sysv.S', 'ffi.c')
if CONFIG['CLANG_CXX']:
if CONFIG['CC_TYPE'] == 'clang':
ASFLAGS += ['-no-integrated-as']
elif CONFIG['FFI_TARGET'] == 'AARCH64':
ffi_srcs = ('sysv.S', 'ffi.c')

2
config/external/icu/common/moz.build поставляемый
Просмотреть файл

@ -11,7 +11,7 @@ DEFINES['U_COMMON_IMPLEMENTATION'] = True
LOCAL_INCLUDES += ['/intl/icu/source/i18n']
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += [
'-Wno-deprecated-declarations',
'-Wno-type-limits',

6
config/external/icu/defs.mozbuild поставляемый
Просмотреть файл

@ -27,7 +27,7 @@ if CONFIG['MOZ_DEBUG']:
DEFINES['U_DEBUG'] = 1
# ICU requires RTTI
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-frtti']
elif CONFIG['OS_TARGET'] == 'WINNT':
CXXFLAGS += ['-GR']
@ -37,7 +37,7 @@ AllowCompilerWarnings()
# We allow compiler warnings, but we can at least cut down on spammy
# warnings that get triggered for every file.
if CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'clang-cl':
CFLAGS += [
'-Wno-macro-redefined',
'-Wno-microsoft-include',
@ -47,7 +47,7 @@ if CONFIG['CLANG_CL']:
'-Wno-microsoft-include',
]
if CONFIG['_MSC_VER'] and not CONFIG['CLANG_CL']:
if CONFIG['CC_TYPE'] == 'msvc':
CFLAGS += [
'-wd4005', # 'WIN32_LEAN_AND_MEAN' : macro redefinition
'-wd4996', # The compiler encountered a deprecated declaration.

Просмотреть файл

@ -35,7 +35,7 @@ PYTHON_UNITTEST_MANIFESTS += [
'tests/python.ini',
]
if CONFIG['GNU_CC'] and CONFIG['MOZ_OPTIMIZE']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc') and CONFIG['MOZ_OPTIMIZE']:
CFLAGS += ['-O3']
HOST_DEFINES = {
@ -46,9 +46,9 @@ HOST_DEFINES = {
include('stl-headers.mozbuild')
if CONFIG['WRAP_STL_INCLUDES']:
stl_compiler = None
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
stl_compiler = 'gcc'
elif CONFIG['_MSC_VER']:
elif CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
stl_compiler = 'msvc'
if stl_compiler:

Просмотреть файл

@ -94,7 +94,7 @@ elif CONFIG['HAVE_64BIT_BUILD']:
DEFINES['SQLITE_TEMP_STORE'] = 2
# Suppress warnings in third-party code.
if CONFIG['GNU_CC']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CFLAGS += [
'-Wno-sign-compare',
'-Wno-type-limits',

345
devtools/bootstrap.js поставляемый
Просмотреть файл

@ -1,345 +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/. */
/* global content, APP_SHUTDOWN */
/* exported startup, shutdown, install, uninstall */
"use strict";
const Cu = Components.utils;
const Ci = Components.interfaces;
const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
// MultiWindowKeyListener instance for Ctrl+Alt+R key
let listener;
// nsIURI to the addon root folder
let resourceURI;
function actionOccurred(id) {
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let Telemetry = require("devtools/client/shared/telemetry");
let telemetry = new Telemetry();
telemetry.actionOccurred(id);
}
// Synchronously fetch the content of a given URL
function readURI(uri) {
let stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true}
).open2();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8"
});
stream.close();
return data;
}
/**
* Interpret the processing instructions contained in a preferences file, based on a
* limited set of supported #if statements. After we ship as an addon, we don't want to
* introduce anymore processing instructions, so all unrecognized preprocessing
* instructions will be treated as an error.
*
* This function is mostly copied from devtools/client/inspector/webpack/prefs-loader.js
*
* @param {String} content
* The string content of a preferences file.
* @return {String} the content stripped of preprocessing instructions.
*/
function interpretPreprocessingInstructions(content) {
const ifMap = {
"#if MOZ_UPDATE_CHANNEL == beta": AppConstants.MOZ_UPDATE_CHANNEL === "beta",
"#if defined(NIGHTLY_BUILD)": AppConstants.NIGHTLY_BUILD,
"#ifdef MOZ_DEV_EDITION": AppConstants.MOZ_DEV_EDITION,
"#ifdef RELEASE_OR_BETA": AppConstants.RELEASE_OR_BETA,
};
let lines = content.split("\n");
let ignoring = false;
let newLines = [];
let continuation = false;
for (let line of lines) {
if (line.startsWith("#if")) {
if (!(line in ifMap)) {
throw new Error("missing line in ifMap: " + line);
}
ignoring = !ifMap[line];
} else if (line.startsWith("#else")) {
ignoring = !ignoring;
} else if (line.startsWith("#endif")) {
ignoring = false;
}
let isPrefLine = /^ *(sticky_)?pref\("([^"]+)"/.test(line);
if (continuation || (!ignoring && isPrefLine)) {
newLines.push(line);
// The call to pref(...); might span more than one line.
continuation = !/\);/.test(line);
}
}
return newLines.join("\n");
}
// Read a preference file and set all of its defined pref as default values
// (This replicates the behavior of preferences files from mozilla-central)
function processPrefFile(url) {
let content = readURI(url);
content = interpretPreprocessingInstructions(content);
content.match(/pref\("[^"]+",\s*.+\s*\)/g).forEach(item => {
let m = item.match(/pref\("([^"]+)",\s*(.+)\s*\)/);
let name = m[1];
let val = m[2].trim();
// Prevent overriding prefs that have been changed by the user
if (Services.prefs.prefHasUserValue(name)) {
return;
}
let defaultBranch = Services.prefs.getDefaultBranch("");
if ((val.startsWith("\"") && val.endsWith("\"")) ||
(val.startsWith("'") && val.endsWith("'"))) {
val = val.substr(1, val.length - 2);
val = val.replace(/\\"/g, '"');
defaultBranch.setCharPref(name, val);
} else if (val.match(/[0-9]+/)) {
defaultBranch.setIntPref(name, parseInt(val, 10));
} else if (val == "true" || val == "false") {
defaultBranch.setBoolPref(name, val == "true");
} else {
console.log("Unable to match preference type for value:", val);
}
});
}
function setPrefs() {
processPrefFile(resourceURI.spec + "./client/preferences/devtools.js");
processPrefFile(resourceURI.spec + "./client/preferences/debugger.js");
processPrefFile(resourceURI.spec + "./client/webide/webide-prefs.js");
}
// Helper to listen to a key on all windows
function MultiWindowKeyListener({ keyCode, ctrlKey, altKey, callback }) {
let keyListener = function (event) {
if (event.ctrlKey == !!ctrlKey &&
event.altKey == !!altKey &&
event.keyCode === keyCode) {
callback(event);
// Call preventDefault to avoid duplicated events when
// doing the key stroke within a tab.
event.preventDefault();
}
};
let observer = function (window, topic, data) {
// Listen on keyup to call keyListener only once per stroke
if (topic === "domwindowopened") {
window.addEventListener("keyup", keyListener);
} else {
window.removeEventListener("keyup", keyListener);
}
};
return {
start: function () {
// Automatically process already opened windows
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowopened", null);
}
// And listen for new ones to come
Services.ww.registerNotification(observer);
},
stop: function () {
Services.ww.unregisterNotification(observer);
let e = Services.ww.getWindowEnumerator();
while (e.hasMoreElements()) {
let window = e.getNext();
observer(window, "domwindowclosed", null);
}
}
};
}
let getTopLevelWindow = function (window) {
return window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
};
function unload(reason) {
// This frame script is going to be executed in all processes:
// parent and child
Services.ppmm.loadProcessScript("data:,(" + function (scriptReason) {
/* Flush message manager cached frame scripts as well as chrome locales */
let obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
obs.notifyObservers(null, "message-manager-flush-caches");
/* Also purge cached modules in child processes, we do it a few lines after
in the parent process */
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
Services.obs.notifyObservers(null, "devtools-unload", scriptReason);
}
} + ")(\"" + reason.replace(/"/g, '\\"') + "\")", false);
// As we can't get a reference to existing Loader.jsm instances, we send them
// an observer service notification to unload them.
Services.obs.notifyObservers(null, "devtools-unload", reason);
// Then spawn a brand new Loader.jsm instance and start the main module
Cu.unload("resource://devtools/shared/Loader.jsm");
// Also unload all resources loaded as jsm, hopefully all of them are going
// to be converted into regular modules
Cu.unload("resource://devtools/client/shared/browser-loader.js");
Cu.unload("resource://devtools/client/framework/ToolboxProcess.jsm");
Cu.unload("resource://devtools/shared/apps/Devices.jsm");
Cu.unload("resource://devtools/client/scratchpad/scratchpad-manager.jsm");
Cu.unload("resource://devtools/shared/Parser.jsm");
Cu.unload("resource://devtools/client/shared/DOMHelpers.jsm");
Cu.unload("resource://devtools/client/shared/widgets/VariablesView.jsm");
Cu.unload("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm");
Cu.unload("resource://devtools/shared/deprecated-sync-thenables.js");
}
function reload(event) {
// We automatically reload the toolbox if we are on a browser tab
// with a toolbox already opened
let reloadToolbox = false;
if (event) {
let top = getTopLevelWindow(event.view);
let isBrowser = top.location.href.includes("/browser.xul");
if (isBrowser && top.gBrowser) {
// We do not use any devtools code before the call to Loader.jsm reload as
// any attempt to use Loader.jsm to load a module will instanciate a new
// Loader.
let nbox = top.gBrowser.getNotificationBox();
reloadToolbox =
top.document.getAnonymousElementByAttribute(nbox, "class",
"devtools-toolbox-bottom-iframe") ||
top.document.getAnonymousElementByAttribute(nbox, "class",
"devtools-toolbox-side-iframe") ||
Services.wm.getMostRecentWindow("devtools:toolbox");
}
}
let browserConsole = Services.wm.getMostRecentWindow("devtools:webconsole");
let reopenBrowserConsole = false;
if (browserConsole) {
browserConsole.close();
reopenBrowserConsole = true;
}
dump("Reload DevTools. (reload-toolbox:" + reloadToolbox + ")\n");
// Invalidate xul cache in order to see changes made to chrome:// files
Services.obs.notifyObservers(null, "startupcache-invalidate");
unload("reload");
// Update the preferences before starting new code
setPrefs();
const {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {});
devtools.require("devtools/client/framework/devtools-browser");
// Go over all top level windows to reload all devtools related things
let windowsEnum = Services.wm.getEnumerator(null);
while (windowsEnum.hasMoreElements()) {
let window = windowsEnum.getNext();
let windowtype = window.document.documentElement.getAttribute("windowtype");
if (windowtype == "navigator:browser" && window.gBrowser) {
// Enumerate tabs on firefox windows
for (let tab of window.gBrowser.tabs) {
let browser = tab.linkedBrowser;
let location = browser.documentURI.spec;
let mm = browser.messageManager;
// To reload JSON-View tabs and any devtools document
if (location.startsWith("about:debugging") ||
location.startsWith("chrome://devtools/")) {
browser.reload();
}
// We have to use a frame script to query "baseURI"
mm.loadFrameScript("data:text/javascript,new " + function () {
let isJSONView =
content.document.baseURI.startsWith("resource://devtools/");
if (isJSONView) {
content.location.reload();
}
}, false);
}
} else if (windowtype === "devtools:webide") {
window.location.reload();
}
}
if (reloadToolbox) {
// Reopen the toolbox automatically if we are reloading from toolbox
// shortcut and are on a browser window.
// Wait for a second before opening the toolbox to avoid races
// between the old and the new one.
let {setTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
setTimeout(() => {
let { TargetFactory } = devtools.require("devtools/client/framework/target");
let { gDevTools } = devtools.require("devtools/client/framework/devtools");
let top = getTopLevelWindow(event.view);
let target = TargetFactory.forTab(top.gBrowser.selectedTab);
gDevTools.showToolbox(target);
}, 1000);
}
// Browser console document can't just be reloaded.
// HUDService is going to close it on unload.
// Instead we have to manually toggle it.
if (reopenBrowserConsole) {
let {HUDService} = devtools.require("devtools/client/webconsole/hudservice");
HUDService.toggleBrowserConsole();
}
actionOccurred("reloadAddonReload");
}
function startup(data) {
dump("DevTools addon started.\n");
resourceURI = data.resourceURI;
listener = new MultiWindowKeyListener({
keyCode: Ci.nsIDOMKeyEvent.DOM_VK_R, ctrlKey: true, altKey: true,
callback: reload
});
listener.start();
reload();
}
function shutdown(data, reason) {
// On browser shutdown, do not try to cleanup anything
if (reason == APP_SHUTDOWN) {
return;
}
listener.stop();
listener = null;
unload("disable");
}
function install() {
try {
actionOccurred("reloadAddonInstalled");
} catch (e) {
// When installing on Firefox builds without devtools, telemetry doesn't
// work yet and throws.
}
}
function uninstall() {}

Просмотреть файл

@ -1,9 +0,0 @@
content devtools client/
skin devtools classic/1.0 client/themes/
resource devtools .
locale devtools en-US client/locales/en-US/
locale devtools-shared en-US shared/locales/en-US/
locale devtools-shim en-US shim/locales/en-US/
content webide client/webide/content/
skin webide classic/1.0 client/webide/themes/

Просмотреть файл

@ -49,10 +49,6 @@ Object.defineProperty(this, "browser", {
* same lifetime as the browser.
*/
let gDevToolsMethods = [
// Used by the reload addon.
// Force reloading dependencies if the loader happens to have reloaded.
"reload",
// Used by: - b2g desktop.js
// - nsContextMenu
// - /devtools code
@ -139,7 +135,7 @@ let gDevToolsBrowserMethods = [
// Used by browser.js
"registerBrowserWindow",
// Used by reload addon
// Used by devtools-browser.js for the Toggle Toolbox status
"hasToolboxOpened",
// Used by browser.js

Просмотреть файл

@ -173,12 +173,6 @@ Telemetry.prototype = {
histogram: "DEVTOOLS_CUSTOM_OPENED_COUNT",
timerHistogram: "DEVTOOLS_CUSTOM_TIME_ACTIVE_SECONDS"
},
reloadAddonInstalled: {
histogram: "DEVTOOLS_RELOAD_ADDON_INSTALLED_COUNT",
},
reloadAddonReload: {
histogram: "DEVTOOLS_RELOAD_ADDON_RELOAD_COUNT",
},
gridInspectorShowGridAreasOverlayChecked: {
scalar: "devtools.grid.showGridAreasOverlay.checked",
},

Просмотреть файл

@ -227,12 +227,23 @@ function enableNetProvider(hud) {
}
}
// Process all incoming HTTP details packets.
// Process all incoming HTTP details packets. Note that
// Network event update packets are sent in batches from:
// `NewConsoleOutputWrapper.dispatchMessageUpdate` using
// NETWORK_MESSAGE_UPDATE action.
// Make sure to call `dataProvider.onNetworkEventUpdate`
// to fetch data from the backend.
if (type == NETWORK_MESSAGE_UPDATE) {
let actor = action.response.networkInfo.actor;
let open = getAllMessagesUiById(state).includes(actor);
if (open) {
dataProvider.onNetworkEventUpdate(null, action.response);
let message = getMessage(state, actor);
message.updates.forEach(updateType => {
dataProvider.onNetworkEventUpdate(null, {
packet: { updateType },
networkInfo: message,
});
});
}
}

Просмотреть файл

@ -7,6 +7,7 @@ support-files =
code_bundle_nosource.js
code_bundle_nosource.js.map
head.js
sjs_slow-response-test-server.sjs
source-mapped.css
source-mapped.css.map
source-mapped.scss
@ -212,6 +213,8 @@ skip-if = true # Bug 1403188
[browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js]
[browser_jsterm_completion.js]
[browser_jsterm_copy_command.js]
[browser_jsterm_ctrl_key_nav.js]
skip-if = os != 'mac' # The tested ctrl+key shortcuts are OSX only
[browser_jsterm_dollar.js]
[browser_jsterm_history.js]
[browser_jsterm_history_persist.js]
@ -264,9 +267,6 @@ skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these o
[browser_webconsole_cspro.js]
skip-if = true # Bug 1408932
# old console skip-if = e10s && (os == 'win' || os == 'mac') # Bug 1243967
[browser_webconsole_ctrl_key_nav.js]
skip-if = true # Bug 1408933
# old console skip-if = os != "mac"
[browser_webconsole_document_focus.js]
skip-if = true # Bug 1404368
[browser_webconsole_duplicate_errors.js]

Просмотреть файл

@ -5,46 +5,39 @@
// Test navigation of webconsole contents via ctrl-a, ctrl-e, ctrl-p, ctrl-n
// see https://bugzilla.mozilla.org/show_bug.cgi?id=804845
//
// The shortcuts tested here have platform limitations:
// - ctrl-e does not work on windows,
// - ctrl-a, ctrl-p and ctrl-n only work on OSX
"use strict";
const TEST_URI = "data:text/html;charset=utf-8,Web Console test for " +
"bug 804845 and bug 619598";
var jsterm, inputNode;
add_task(async function () {
const {jsterm} = await openNewTabAndConsole(TEST_URI);
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
doTests(hud);
jsterm = inputNode = null;
});
function doTests(HUD) {
jsterm = HUD.jsterm;
inputNode = jsterm.inputNode;
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
is(jsterm.inputNode.selectionStart, 0);
is(jsterm.inputNode.selectionEnd, 0);
testSingleLineInputNavNoHistory();
testMultiLineInputNavNoHistory();
testNavWithHistory();
}
testSingleLineInputNavNoHistory(jsterm);
testMultiLineInputNavNoHistory(jsterm);
testNavWithHistory(jsterm);
});
function testSingleLineInputNavNoHistory() {
function testSingleLineInputNavNoHistory(jsterm) {
let inputNode = jsterm.inputNode;
// Single char input
EventUtils.synthesizeKey("1", {});
is(inputNode.selectionStart, 1, "caret location after single char input");
// nav to start/end with ctrl-a and ctrl-e;
EventUtils.synthesizeKey("a", { ctrlKey: true });
synthesizeLineStartKey();
is(inputNode.selectionStart, 0,
"caret location after single char input and ctrl-a");
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
is(inputNode.selectionStart, 1,
"caret location after single char input and ctrl-e");
@ -58,34 +51,35 @@ function testSingleLineInputNavNoHistory() {
is(inputNode.selectionStart, 2,
"caret location after two char input and VK_DOWN");
EventUtils.synthesizeKey("a", { ctrlKey: true });
synthesizeLineStartKey();
is(inputNode.selectionStart, 0,
"move caret to beginning of 2 char input with ctrl-a");
EventUtils.synthesizeKey("a", { ctrlKey: true });
synthesizeLineStartKey();
is(inputNode.selectionStart, 0,
"no change of caret location on repeat ctrl-a");
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(inputNode.selectionStart, 0,
"no change of caret location on ctrl-p from beginning of line");
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
is(inputNode.selectionStart, 2,
"move caret to end of 2 char input with ctrl-e");
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
is(inputNode.selectionStart, 2,
"no change of caret location on repeat ctrl-e");
EventUtils.synthesizeKey("n", { ctrlKey: true });
synthesizeLineDownKey();
is(inputNode.selectionStart, 2,
"no change of caret location on ctrl-n from end of line");
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(inputNode.selectionStart, 0, "ctrl-p moves to start of line");
EventUtils.synthesizeKey("n", { ctrlKey: true });
synthesizeLineDownKey();
is(inputNode.selectionStart, 2, "ctrl-n moves to end of line");
}
function testMultiLineInputNavNoHistory() {
function testMultiLineInputNavNoHistory(jsterm) {
let inputNode = jsterm.inputNode;
let lineValues = ["one", "2", "something longer", "", "", "three!"];
jsterm.setInputValue("");
// simulate shift-return
@ -113,43 +107,43 @@ function testMultiLineInputNavNoHistory() {
"down arrow from within multiline");
// navigate up through input lines
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(jsterm.getInputValue().slice(inputNode.selectionStart), expectedStringAfterCarat,
"ctrl-p from end of multiline");
for (let i = 4; i >= 0; i--) {
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
expectedStringAfterCarat = lineValues[i] + newlineString +
expectedStringAfterCarat;
is(jsterm.getInputValue().slice(inputNode.selectionStart),
expectedStringAfterCarat, "ctrl-p from within line " + i +
" of multiline input");
}
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(inputNode.selectionStart, 0, "reached start of input");
is(jsterm.getInputValue(), inputValue,
"no change to multiline input on ctrl-p from beginning of multiline");
// navigate to end of first line
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
let caretPos = inputNode.selectionStart;
let expectedStringBeforeCarat = lineValues[0];
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
"ctrl-e into multiline input");
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
is(inputNode.selectionStart, caretPos,
"repeat ctrl-e doesn't change caret position in multiline input");
// navigate down one line; ctrl-a to the beginning; ctrl-e to end
for (let i = 1; i < lineValues.length; i++) {
EventUtils.synthesizeKey("n", { ctrlKey: true });
EventUtils.synthesizeKey("a", { ctrlKey: true });
synthesizeLineDownKey();
synthesizeLineStartKey();
caretPos = inputNode.selectionStart;
expectedStringBeforeCarat += newlineString;
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
"ctrl-a to beginning of line " + (i + 1) + " in multiline input");
EventUtils.synthesizeKey("e", { ctrlKey: true });
synthesizeLineEndKey();
caretPos = inputNode.selectionStart;
expectedStringBeforeCarat += lineValues[i];
is(jsterm.getInputValue().slice(0, caretPos), expectedStringBeforeCarat,
@ -157,13 +151,17 @@ function testMultiLineInputNavNoHistory() {
}
}
function testNavWithHistory() {
function testNavWithHistory(jsterm) {
let inputNode = jsterm.inputNode;
// NOTE: Tests does NOT currently define behaviour for ctrl-p/ctrl-n with
// caret placed _within_ single line input
let values = ['"single line input"',
'"a longer single-line input to check caret repositioning"',
['"multi-line"', '"input"', '"here!"'].join("\n"),
];
let values = [
'"single line input"',
'"a longer single-line input to check caret repositioning"',
'"multi-line"\n"input"\n"here!"',
];
// submit to history
for (let i = 0; i < values.length; i++) {
jsterm.setInputValue(values[i]);
@ -171,7 +169,7 @@ function testNavWithHistory() {
}
is(inputNode.selectionStart, 0, "caret location at start of empty line");
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(inputNode.selectionStart, values[values.length - 1].length,
"caret location correct at end of last history input");
@ -180,20 +178,21 @@ function testNavWithHistory() {
let match = values[i].match(/(\n)/g);
if (match) {
// multi-line inputs won't update from history unless caret at beginning
EventUtils.synthesizeKey("a", { ctrlKey: true });
synthesizeLineStartKey();
for (let j = 0; j < match.length; j++) {
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
}
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
} else {
// single-line inputs will update from history from end of line
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
}
is(jsterm.getInputValue(), values[i - 1],
"ctrl-p updates inputNode from backwards history values[" + i - 1 + "]");
}
let inputValue = jsterm.getInputValue();
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(inputNode.selectionStart, 0,
"ctrl-p at beginning of history moves caret location to beginning " +
"of line");
@ -202,13 +201,13 @@ function testNavWithHistory() {
// Navigate forwards history with ctrl-n
for (let i = 1; i < values.length; i++) {
EventUtils.synthesizeKey("n", { ctrlKey: true });
synthesizeLineDownKey();
is(jsterm.getInputValue(), values[i],
"ctrl-n updates inputNode from forwards history values[" + i + "]");
is(inputNode.selectionStart, values[i].length,
"caret location correct at end of history input for values[" + i + "]");
}
EventUtils.synthesizeKey("n", { ctrlKey: true });
synthesizeLineDownKey();
ok(!jsterm.getInputValue(), "ctrl-n at end of history updates to empty input");
// Simulate editing multi-line
@ -216,12 +215,28 @@ function testNavWithHistory() {
jsterm.setInputValue(inputValue);
// Attempt nav within input
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineUpKey();
is(jsterm.getInputValue(), inputValue,
"ctrl-p from end of multi-line does not trigger history");
EventUtils.synthesizeKey("a", { ctrlKey: true });
EventUtils.synthesizeKey("p", { ctrlKey: true });
synthesizeLineStartKey();
synthesizeLineUpKey();
is(jsterm.getInputValue(), values[values.length - 1],
"ctrl-p from start of multi-line triggers history");
}
function synthesizeLineStartKey() {
EventUtils.synthesizeKey("a", { ctrlKey: true });
}
function synthesizeLineEndKey() {
EventUtils.synthesizeKey("e", { ctrlKey: true });
}
function synthesizeLineUpKey() {
EventUtils.synthesizeKey("p", { ctrlKey: true });
}
function synthesizeLineDownKey() {
EventUtils.synthesizeKey("n", { ctrlKey: true });
}

Просмотреть файл

@ -17,53 +17,189 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref(XHR_PREF);
});
let tabs = [{
id: "headers",
testEmpty: testEmptyHeaders,
testContent: testHeaders,
}, {
id: "cookies",
testEmpty: testEmptyCookies,
testContent: testCookies,
}, {
id: "params",
testEmpty: testEmptyParams,
testContent: testParams,
}, {
id: "response",
testEmpty: testEmptyResponse,
testContent: testResponse,
}, {
id: "timings",
testEmpty: testEmptyTimings,
testContent: testTimings,
}, {
id: "stack-trace",
testEmpty: testEmptyStackTrace,
testContent: testStackTrace,
}];
/**
* Main test for checking HTTP logs in the Console panel.
*/
add_task(async function task() {
const hud = await openNewTabAndConsole(TEST_URI);
const currentTab = gBrowser.selectedTab;
let target = TargetFactory.forTab(currentTab);
// Execute XHR and expand it after all network
// update events are received. Consequently,
// check out content of all (HTTP details) tabs.
await openRequestAfterUpdates(target, hud);
// Test proper UI update when request is opened.
// For every tab (with HTTP details):
// 1. Execute long-time request
// 2. Expand the net log before the request finishes (set default tab)
// 3. Check the default tab empty content
// 4. Wait till the request finishes
// 5. Check content of all tabs
for (let tab of tabs) {
await openRequestBeforeUpdates(target, hud, tab);
}
});
async function openRequestAfterUpdates(target, hud) {
let toolbox = gDevTools.getToolbox(target);
let xhrUrl = TEST_PATH + "sjs_slow-response-test-server.sjs";
let message = waitForMessage(hud, xhrUrl);
// Fire an XHR POST request.
await ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
content.wrappedJSObject.testXhrPost();
ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
content.wrappedJSObject.testXhrPostSlowResponse();
});
info("XHR executed");
let { node: messageNode } = await message;
info("Network message found.");
await waitForRequestUpdates(toolbox);
let xhrUrl = TEST_PATH + "test-data.json";
let messageNode = await waitFor(() => findMessage(hud, xhrUrl));
let urlNode = messageNode.querySelector(".url");
info("Network message found.");
let updates = waitForPayloadReady(toolbox);
let payload = waitForPayloadReady(toolbox);
// Expand network log
let urlNode = messageNode.querySelector(".url");
urlNode.click();
await payload;
await testNetworkMessage(toolbox, messageNode);
}
async function openRequestBeforeUpdates(target, hud, tab) {
let toolbox = gDevTools.getToolbox(target);
hud.jsterm.clearOutput(true);
let xhrUrl = TEST_PATH + "sjs_slow-response-test-server.sjs";
let message = waitForMessage(hud, xhrUrl);
// Fire an XHR POST request.
ContentTask.spawn(gBrowser.selectedBrowser, null, function () {
content.wrappedJSObject.testXhrPostSlowResponse();
});
let { node: messageNode } = await message;
info("Network message found.");
let updates = waitForRequestUpdates(toolbox);
let payload = waitForPayloadReady(toolbox);
// Set the default panel.
const state = hud.ui.newConsoleOutput.getStore().getState();
state.ui.networkMessageActiveTabId = tab.id;
// Expand network log
let urlNode = messageNode.querySelector(".url");
urlNode.click();
// Make sure the current tab is the expected one.
let currentTab = messageNode.querySelector(`#${tab.id}-tab`);
is(currentTab.getAttribute("aria-selected"), "true",
"The correct tab is selected");
// The tab should be empty now.
tab.testEmpty(messageNode);
// Wait till all updates and payload are received.
await updates;
await testNetworkMessage(messageNode);
});
await payload;
async function testNetworkMessage(messageNode) {
// Test content of the default tab.
await tab.testContent(messageNode);
// Test all tabs in the network log.
await testNetworkMessage(toolbox, messageNode);
}
// Panel testing helpers
async function testNetworkMessage(toolbox, messageNode) {
await testHeaders(messageNode);
await testCookies(messageNode);
await testParams(messageNode);
await testResponse(messageNode);
await testTimings(messageNode);
await testStackTrace(messageNode);
await waitForLazyRequests(toolbox);
}
// Headers
function testEmptyHeaders(messageNode) {
let emptyNotice = messageNode.querySelector("#headers-panel .empty-notice");
ok(emptyNotice, "Headers tab is empty");
}
async function testHeaders(messageNode) {
let headersTab = messageNode.querySelector("#headers-tab");
let cookiesTab = messageNode.querySelector("#cookies-tab");
let paramsTab = messageNode.querySelector("#params-tab");
let responseTab = messageNode.querySelector("#response-tab");
let timingsTab = messageNode.querySelector("#timings-tab");
ok(headersTab, "Headers tab is available");
ok(cookiesTab, "Cookies tab is available");
ok(paramsTab, "Params tab is available");
ok(responseTab, "Response tab is available");
ok(timingsTab, "Timings tab is available");
// Headers tab should be selected by default, so just check its content.
let headersContent = messageNode.querySelector(
"#headers-panel .headers-overview");
ok(headersContent, "Headers content is available");
// Select Headers tab and check the content.
headersTab.click();
await waitUntil(() => {
return !!messageNode.querySelector("#headers-panel .headers-overview");
});
}
// Cookies
function testEmptyCookies(messageNode) {
let emptyNotice = messageNode.querySelector("#cookies-panel .empty-notice");
ok(emptyNotice, "Cookies tab is empty");
}
async function testCookies(messageNode) {
let cookiesTab = messageNode.querySelector("#cookies-tab");
ok(cookiesTab, "Cookies tab is available");
// Select tab and check the content.
cookiesTab.click();
await waitUntil(() => {
return !!messageNode.querySelector("#cookies-panel .treeValueCell");
});
}
// Params
function testEmptyParams(messageNode) {
let emptyNotice = messageNode.querySelector("#params-panel .empty-notice");
ok(emptyNotice, "Params tab is empty");
}
async function testParams(messageNode) {
let paramsTab = messageNode.querySelector("#params-tab");
ok(paramsTab, "Params tab is available");
// Select Params tab and check the content. CodeMirror initialization
// is delayed to prevent UI freeze, so wait for a little while.
@ -74,6 +210,18 @@ async function testNetworkMessage(messageNode) {
"#params-panel .panel-container .CodeMirror");
ok(paramsContent, "Params content is available");
ok(paramsContent.textContent.includes("Hello world!"), "Post body is correct");
}
// Response
function testEmptyResponse(messageNode) {
let panel = messageNode.querySelector("#response-panel .tab-panel");
is(panel.textContent, "", "Cookies tab is empty");
}
async function testResponse(messageNode) {
let responseTab = messageNode.querySelector("#response-tab");
ok(responseTab, "Response tab is available");
// Select Response tab and check the content. CodeMirror initialization
// is delayed, so again wait for a little while.
@ -84,6 +232,18 @@ async function testNetworkMessage(messageNode) {
"#response-panel .editor-row-container .CodeMirror");
ok(responseContent, "Response content is available");
ok(responseContent.textContent, "Response text is available");
}
// Timings
function testEmptyTimings(messageNode) {
let panel = messageNode.querySelector("#timings-panel .tab-panel");
is(panel.textContent, "", "Timings tab is empty");
}
async function testTimings(messageNode) {
let timingsTab = messageNode.querySelector("#timings-tab");
ok(timingsTab, "Timings tab is available");
// Select Timings tab and check the content.
timingsTab.click();
@ -93,6 +253,26 @@ async function testNetworkMessage(messageNode) {
ok(timingsContent.textContent, "Timings text is available");
}
// Stack Trace
function testEmptyStackTrace(messageNode) {
let panel = messageNode.querySelector("#stack-trace-panel .stack-trace");
is(panel.textContent, "", "StackTrace tab is empty");
}
async function testStackTrace(messageNode) {
let stackTraceTab = messageNode.querySelector("#stack-trace-tab");
ok(stackTraceTab, "StackTrace tab is available");
// Select Timings tab and check the content.
stackTraceTab.click();
await waitUntil(() => {
return !!messageNode.querySelector("#stack-trace-panel .frame-link");
});
}
// Waiting helpers
async function waitForPayloadReady(toolbox) {
let {ui} = toolbox.getCurrentPanel().hud;
return new Promise(resolve => {
@ -118,3 +298,11 @@ async function waitForRequestUpdates(toolbox) {
});
});
}
async function waitForLazyRequests(toolbox) {
let {ui} = toolbox.getCurrentPanel().hud;
let proxy = ui.jsterm.hud.proxy;
return waitUntil(() => {
return !proxy.networkDataProvider.lazyRequestData.size;
});
}

Просмотреть файл

@ -0,0 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const { classes: Cc, interfaces: Ci } = Components;
function handleRequest(request, response) {
response.processAsync();
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(() => {
// to avoid garbage collection
timer = null;
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/plain", false);
response.setHeader("Set-Cookie", "foo=bar; Max-Age=10; HttpOnly", true);
response.write("Some response data");
response.finish();
}, 300, Ci.nsITimer.TYPE_ONE_SHOT); // Make sure this request takes a few hundred ms.
}

Просмотреть файл

@ -7,7 +7,7 @@
<meta charset="utf-8">
<title>Console HTTP test page</title>
<script type="text/javascript">
/* exported testXhrGet, testXhrWarn, testXhrPost */
/* exported testXhrGet, testXhrWarn, testXhrPost, testXhrPostSlowResponse */
"use strict";
function makeXhr(method, url, requestBody, callback) {
@ -32,6 +32,10 @@
function testXhrPost(callback) {
makeXhr("post", "test-data.json", "Hello world!", callback);
}
function testXhrPostSlowResponse(callback) {
makeXhr("post", "sjs_slow-response-test-server.sjs", "Hello world!", callback);
}
</script>
</head>
<body>

Просмотреть файл

@ -1,29 +0,0 @@
<?xml version="1.0"?>
<!--
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest"
em:id="devtools@mozilla.org"
em:name="Developer Tools"
em:description="System-addon for Firefox DevTools"
em:version="44.0a1"
em:type="2"
em:creator="Mozilla">
<em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<!-- Valid for all toolkit applications -->
<em:targetApplication>
<Description>
<em:id>toolkit@mozilla.org</em:id>
<em:minVersion>57.0a1</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

Просмотреть файл

@ -58,5 +58,5 @@ DevToolsModules(
'shortest-paths.js',
)
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -23,12 +23,12 @@ UNIFIED_SOURCES = [
'SerializesTypeNames.cpp',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
# THE MOCK_METHOD2 macro from gtest triggers this clang warning and it's hard
# to work around, so we just ignore it.
if CONFIG['CLANG_CXX']:
if CONFIG['CC_TYPE'] == 'clang':
CXXFLAGS += ['-Wno-inconsistent-missing-override']
# Workaround bug 1142396. Suppress the warning from gmock library for clang.
CXXFLAGS += ['-Wno-null-dereference']

Просмотреть файл

@ -122,5 +122,5 @@ LOCAL_INCLUDES += [
if CONFIG['MOZ_TOOLKIT_SEARCH']:
DEFINES['MOZ_TOOLKIT_SEARCH'] = True
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -36,5 +36,5 @@ LOCAL_INCLUDES += [
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -13,10 +13,10 @@ Test chrome-only MutationObserver animation notifications (async tests)
in test_animation_observers_sync.html.
-->
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="../testharness.js"></script>
<script type="application/javascript" src="../testharnessreport.js"></script>
<script src="../testcommon.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<div id="log"></div>
<style>
@keyframes anim {
to { transform: translate(100px); }
@ -39,72 +39,13 @@ var gObserver = new MutationObserver(newRecords => {
gRecords.push(...newRecords);
});
// Asynchronous testing framework based on layout/style/test/animation_utils.js.
var gTests = [];
var gCurrentTestName;
function addAsyncAnimTest(aName, aOptions, aTestGenerator) {
aTestGenerator.testName = aName;
aTestGenerator.options = aOptions || {};
gTests.push(aTestGenerator);
}
function runAsyncTest(aTestGenerator) {
return waitForFrame().then(() => {
var generator;
function step(arg) {
var next;
try {
next = generator.next(arg);
} catch (e) {
return Promise.reject(e);
}
if (next.done) {
return Promise.resolve(next.value);
} else {
return Promise.resolve(next.value).then(step);
}
}
var subtree = aTestGenerator.options.subtree;
gCurrentTestName = aTestGenerator.testName;
if (subtree) {
gCurrentTestName += ":subtree";
}
gRecords = [];
function setupAsynchronousObserver(t, options) {
gRecords = [];
t.add_cleanup(() => {
gObserver.disconnect();
gObserver.observe(aTestGenerator.options.observe,
{ animations: true, subtree: subtree});
generator = aTestGenerator();
return step();
});
};
function runAllAsyncTests() {
return gTests.reduce((sequence, test) => {
return sequence.then(() => runAsyncTest(test));
}, Promise.resolve());
}
// Wrap is and ok with versions that prepend the current sub-test name
// to the assertion description.
var old_is = is, old_ok = ok;
is = function(a, b, message) {
if (gCurrentTestName && message) {
message = `[${gCurrentTestName}] ${message}`;
}
old_is(a, b, message);
}
ok = function(a, message) {
if (gCurrentTestName && message) {
message = `[${gCurrentTestName}] ${message}`;
}
old_ok(a, message);
gObserver.observe(options.subtree ? div.parentNode : div,
{ animations: true, subtree: options.subtree });
}
// Adds an event listener and returns a Promise that is resolved when the
@ -120,20 +61,21 @@ function await_event(aElement, aEventName) {
}
function assert_record_list(actual, expected, desc, index, listName) {
is(actual.length, expected.length, `${desc} - record[${index}].${listName} length`);
assert_equals(actual.length, expected.length,
`${desc} - record[${index}].${listName} length`);
if (actual.length != expected.length) {
return;
}
for (var i = 0; i < actual.length; i++) {
ok(actual.indexOf(expected[i]) != -1,
`${desc} - record[${index}].${listName} contains expected Animation`);
assert_not_equals(actual.indexOf(expected[i]), -1,
`${desc} - record[${index}].${listName} contains expected Animation`);
}
}
function assert_records(expected, desc) {
var records = gRecords;
gRecords = [];
is(records.length, expected.length, `${desc} - number of records`);
assert_equals(records.length, expected.length, `${desc} - number of records`);
if (records.length != expected.length) {
return;
}
@ -190,267 +132,327 @@ function assert_records_any_order(expected, desc) {
// targeting the div and observing its parent while using the subtree:true
// MutationObserver option.
[
{ observe: div, target: div, subtree: false },
{ observe: div.parentNode, target: div, subtree: true },
].forEach(aOptions => {
function runTest() {
[
{ observe: div, target: div, subtree: false },
{ observe: div.parentNode, target: div, subtree: true },
].forEach(aOptions => {
var e = aOptions.target;
var e = aOptions.target;
// Test that starting a single transition that completes normally
// dispatches an added notification and then a removed notification.
addAsyncAnimTest("single_transition", aOptions, function*() {
// Start a transition.
e.style = "transition: background-color 100s; background-color: lime;";
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
// Clear all styles once test finished since we re-use the same element
// in all test cases.
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Register for the end of the transition.
var transitionEnd = await_event(e, "transitionend");
// Start a transition.
e.style = "transition: background-color 100s; background-color: lime;";
// The transition should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after transition start");
// Register for the end of the transition.
var transitionEnd = await_event(e, "transitionend");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after transition start");
// The transition should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after transition start");
// Advance until near the end of the transition, then wait for it to finish.
animations[0].currentTime = 99900;
yield transitionEnd;
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {
assert_records([{ added: animations, changed: [], removed: [] }],
"records after transition start");
// After the transition has finished, the Animation should disappear.
is(e.getAnimations().length, 0,
"getAnimations().length after transition end");
// Advance until near the end of the transition, then wait for it to
// finish.
animations[0].currentTime = 99900;
}).then(() => {
return transitionEnd;
}).then(() => {
// After the transition has finished, the Animation should disappear.
assert_equals(e.getAnimations().length, 0,
"getAnimations().length after transition end");
// Wait for the change MutationRecord for seeking the Animation to be
// delivered, followed by the the removal MutationRecord.
yield waitForFrame();
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: [], removed: animations }],
"records after transition end");
// Wait for the change MutationRecord for seeking the Animation to be
// delivered, followed by the the removal MutationRecord.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: [], removed: animations }],
"records after transition end");
});
}, `single_transition ${aOptions.subtree ? ': subtree' : ''}`);
e.style = "";
// Test that starting a single animation that completes normally
// dispatches an added notification and then a removed notification.
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Start an animation.
e.style = "animation: anim 100s;";
// Register for the end of the animation.
var animationEnd = await_event(e, "animationend");
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Advance until near the end of the animation, then wait for it to finish.
animations[0].currentTime = 99900;
return animationEnd;
}).then(() => {
// After the animation has finished, the Animation should disappear.
assert_equals(e.getAnimations().length, 0,
"getAnimations().length after animation end");
// Wait for the change MutationRecord from seeking the Animation to
// be delivered, followed by a further MutationRecord for the Animation
// removal.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: [], removed: animations }],
"records after animation end");
});
}, `single_animation ${aOptions.subtree ? ': subtree' : ''}`);
// Test that starting a single animation that is cancelled by updating
// the animation-fill-mode property dispatches an added notification and
// then a removed notification.
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Start a short, filled animation.
e.style = "animation: anim 100s forwards;";
// Register for the end of the animation.
var animationEnd = await_event(e, "animationend");
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Advance until near the end of the animation, then wait for it to finish.
animations[0].currentTime = 99900;
return animationEnd;
}).then(() => {
// The only MutationRecord at this point should be the change from
// seeking the Animation.
assert_records([{ added: [], changed: animations, removed: [] }],
"records after animation starts filling");
// Cancel the animation by setting animation-fill-mode.
e.style.animationFillMode = "none";
// Explicitly flush style to make sure the above style change happens.
// Normally we don't need explicit style flush if there is a waitForFrame()
// call but in this particular case we are in the middle of animation events'
// callback handling and requestAnimationFrame handling so that we have no
// chance to process styling even after the requestAnimationFrame handling.
flushComputedStyle(e);
// Wait for the single MutationRecord for the Animation removal to
// be delivered.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
}, `single_animation_cancelled_fill ${aOptions.subtree ? ': subtree' : ''}`);
// Test that calling finish() on a paused (but otherwise finished) animation
// dispatches a changed notification.
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Start a long animation
e.style = "animation: anim 100s forwards";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Wait until the animation is playing.
return animations[0].ready;
}).then(() => {
// Finish and pause.
animations[0].finish();
animations[0].pause();
// Wait for the pause to complete.
return animations[0].ready;
}).then(() => {
assert_equals(animations[0].playState, "paused",
"playState after finishing and pausing");
// We should have two MutationRecords for the Animation changes:
// one for the finish, one for the pause.
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: animations, removed: [] }],
"records after finish() and pause()");
// Call finish() again.
animations[0].finish();
assert_equals(animations[0].playState, "finished",
"playState after finishing from paused state");
// Wait for the single MutationRecord for the Animation change to
// be delivered. Even though the currentTime does not change, the
// playState will change.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: animations, removed: [] }],
"records after finish() and pause()");
// Cancel the animation.
e.style = "";
// Wait for the single removal notification.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
}, `finish_from_pause ${aOptions.subtree ? ': subtree' : ''}`);
// Test that calling play() on a paused Animation dispatches a changed
// notification.
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Start a long, paused animation
e.style = "animation: anim 100s paused";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Wait until the animation is ready
return animations[0].ready;
}).then(() => {
// Play
animations[0].play();
// Wait for the single MutationRecord for the Animation change to
// be delivered.
return animations[0].ready;
}).then(() => {
assert_records([{ added: [], changed: animations, removed: [] }],
"records after play()");
// Redundant play
animations[0].play();
// Wait to ensure no change is dispatched
return waitForFrame();
}).then(() => {
assert_records([], "records after redundant play()");
// Cancel the animation.
e.style = "";
// Wait for the single removal notification.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
}, `play ${aOptions.subtree ? ': subtree' : ''}`);
// Test that a non-cancelling change to an animation followed immediately by a
// cancelling change will only send an animation removal notification.
promise_test(t => {
setupAsynchronousObserver(t, aOptions);
t.add_cleanup(() => {
e.style = "";
flushComputedStyle(e);
});
// Start a long animation.
e.style = "animation: anim 100s;";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
assert_equals(animations.length, 1,
"getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
return waitForFrame().then(() => {;
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Update the animation's delay such that it is still running.
e.style.animationDelay = "-1s";
// Then cancel the animation by updating its duration.
e.style.animationDuration = "0.5s";
// We should get a single removal notification.
return waitForFrame();
}).then(() => {
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
}, `coalesce_change_cancel ${aOptions.subtree ? ': subtree' : ''}`);
});
}
promise_test(t => {
setupAsynchronousObserver(t, { observe: div, subtree: true });
t.add_cleanup(() => {
div.style = "";
flushComputedStyle(div);
});
// Test that starting a single animation that completes normally
// dispatches an added notification and then a removed notification.
addAsyncAnimTest("single_animation", aOptions, function*() {
// Start an animation.
e.style = "animation: anim 100s;";
// Register for the end of the animation.
var animationEnd = await_event(e, "animationend");
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Advance until near the end of the animation, then wait for it to finish.
animations[0].currentTime = 99900;
yield animationEnd;
// After the animation has finished, the Animation should disappear.
is(e.getAnimations().length, 0,
"getAnimations().length after animation end");
// Wait for the change MutationRecord from seeking the Animation to
// be delivered, followed by a further MutationRecord for the Animation
// removal.
yield waitForFrame();
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: [], removed: animations }],
"records after animation end");
e.style = "";
});
// Test that starting a single animation that is cancelled by updating
// the animation-fill-mode property dispatches an added notification and
// then a removed notification.
addAsyncAnimTest("single_animation_cancelled_fill", aOptions, function*() {
// Start a short, filled animation.
e.style = "animation: anim 100s forwards;";
// Register for the end of the animation.
var animationEnd = await_event(e, "animationend");
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Advance until near the end of the animation, then wait for it to finish.
animations[0].currentTime = 99900;
yield animationEnd;
// The only MutationRecord at this point should be the change from
// seeking the Animation.
assert_records([{ added: [], changed: animations, removed: [] }],
"records after animation starts filling");
// Cancel the animation by setting animation-fill-mode.
e.style.animationFillMode = "none";
// Explicitly flush style to make sure the above style change happens.
// Normally we don't need explicit style flush if there is a waitForFrame()
// call but in this particular case we are in the middle of animation events'
// callback handling and requestAnimationFrame handling so that we have no
// chance to process styling even after the requestAnimationFrame handling.
flushComputedStyle(e);
// Wait for the single MutationRecord for the Animation removal to
// be delivered.
yield waitForFrame();
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
e.style = "";
});
// Test that calling finish() on a paused (but otherwise finished) animation
// dispatches a changed notification.
addAsyncAnimTest("finish_from_pause", aOptions, function*() {
// Start a long animation
e.style = "animation: anim 100s forwards";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Wait until the animation is playing.
yield animations[0].ready;
// Finish and pause.
animations[0].finish();
animations[0].pause();
// Wait for the pause to complete.
yield animations[0].ready;
is(animations[0].playState, "paused",
"playState after finishing and pausing");
// We should have two MutationRecords for the Animation changes:
// one for the finish, one for the pause.
assert_records([{ added: [], changed: animations, removed: [] },
{ added: [], changed: animations, removed: [] }],
"records after finish() and pause()");
// Call finish() again.
animations[0].finish();
is(animations[0].playState, "finished",
"playState after finishing from paused state");
// Wait for the single MutationRecord for the Animation change to
// be delivered. Even though the currentTime does not change, the
// playState will change.
yield waitForFrame();
assert_records([{ added: [], changed: animations, removed: [] }],
"records after finish() and pause()");
// Cancel the animation.
e.style = "";
// Wait for the single removal notification.
yield waitForFrame();
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
// Test that calling play() on a paused Animation dispatches a changed
// notification.
addAsyncAnimTest("play", aOptions, function*() {
// Start a long, paused animation
e.style = "animation: anim 100s paused";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Wait until the animation is ready
yield animations[0].ready;
// Play
animations[0].play();
// Wait for the single MutationRecord for the Animation change to
// be delivered.
yield animations[0].ready;
assert_records([{ added: [], changed: animations, removed: [] }],
"records after play()");
// Redundant play
animations[0].play();
// Wait to ensure no change is dispatched
yield waitForFrame();
assert_records([], "records after redundant play()");
// Cancel the animation.
e.style = "";
// Wait for the single removal notification.
yield waitForFrame();
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
});
// Test that a non-cancelling change to an animation followed immediately by a
// cancelling change will only send an animation removal notification.
addAsyncAnimTest("coalesce_change_cancel", aOptions, function*() {
// Start a long animation.
e.style = "animation: anim 100s;";
// The animation should cause the creation of a single Animation.
var animations = e.getAnimations();
is(animations.length, 1, "getAnimations().length after animation start");
// Wait for the single MutationRecord for the Animation addition to
// be delivered.
yield waitForFrame();
assert_records([{ added: animations, changed: [], removed: [] }],
"records after animation start");
// Update the animation's delay such that it is still running.
e.style.animationDelay = "-1s";
// Then cancel the animation by updating its duration.
e.style.animationDuration = "0.5s";
// We should get a single removal notification.
yield waitForFrame();
assert_records([{ added: [], changed: [], removed: animations }],
"records after animation end");
e.style = "";
});
});
addAsyncAnimTest("tree_ordering", { observe: div, subtree: true }, function*() {
// Add style for pseudo elements
var extraStyle = document.createElement('style');
document.head.appendChild(extraStyle);
@ -491,7 +493,7 @@ addAsyncAnimTest("tree_ordering", { observe: div, subtree: true }, function*() {
// Check all animations we have in this document
var docAnims = document.getAnimations();
is(docAnims.length, 10, "total animations");
assert_equals(docAnims.length, 10, "total animations");
var divAnimations = div.getAnimations();
var childAAnimations = childA.getAnimations();
@ -506,6 +508,7 @@ addAsyncAnimTest("tree_ordering", { observe: div, subtree: true }, function*() {
var childBPseudoAnimations =
docAnims.filter(x => x.effect.target.parentElement == childB);
var seekRecords;
// The order in which we get the corresponding records is currently
// based on the order we visit these nodes when updating styles.
//
@ -513,75 +516,73 @@ addAsyncAnimTest("tree_ordering", { observe: div, subtree: true }, function*() {
// mutation records when we flush styles. We may introduce that in the
// future but for now all we are interested in testing here is that the
// right records are generated, but we allow them to occur in any order.
yield waitForFrame();
assert_records_any_order(
[{ added: divAfterAnimations, changed: [], removed: [] },
{ added: childAAnimations, changed: [], removed: [] },
{ added: childBAnimations, changed: [], removed: [] },
{ added: childBPseudoAnimations, changed: [], removed: [] },
{ added: divAnimations, changed: [], removed: [] },
{ added: divBeforeAnimations, changed: [], removed: [] }],
"records after simultaneous animation start");
return waitForFrame().then(() => {
assert_records_any_order(
[{ added: divAfterAnimations, changed: [], removed: [] },
{ added: childAAnimations, changed: [], removed: [] },
{ added: childBAnimations, changed: [], removed: [] },
{ added: childBPseudoAnimations, changed: [], removed: [] },
{ added: divAnimations, changed: [], removed: [] },
{ added: divBeforeAnimations, changed: [], removed: [] }],
"records after simultaneous animation start");
// The one case where we *do* currently perform document-level (or actually
// timeline-level) batching is when animations are updated from a refresh
// driver tick. In particular, this means that when animations finish
// naturally the removed records should be dispatched according to the
// position of the elements in the tree.
// The one case where we *do* currently perform document-level (or actually
// timeline-level) batching is when animations are updated from a refresh
// driver tick. In particular, this means that when animations finish
// naturally the removed records should be dispatched according to the
// position of the elements in the tree.
// First, flatten the set of animations. we put the animations targeting to
// pseudo elements last. (Actually, we don't care the order in the list.)
var animations = [ ...divAnimations,
...childAAnimations,
...childBAnimations,
...divBeforeAnimations,
...divAfterAnimations,
...childBPseudoAnimations ];
// First, flatten the set of animations. we put the animations targeting to
// pseudo elements last. (Actually, we don't care the order in the list.)
var animations = [ ...divAnimations,
...childAAnimations,
...childBAnimations,
...divBeforeAnimations,
...divAfterAnimations,
...childBPseudoAnimations ];
// Fast-forward to *just* before the end of the animation.
animations.forEach(animation => animation.currentTime = 99999);
// Fast-forward to *just* before the end of the animation.
animations.forEach(animation => animation.currentTime = 99999);
// Prepare the set of expected change MutationRecords, one for each
// animation that was seeked.
var seekRecords = animations.map(
p => ({ added: [], changed: [p], removed: [] })
);
// Prepare the set of expected change MutationRecords, one for each
// animation that was seeked.
seekRecords = animations.map(
p => ({ added: [], changed: [p], removed: [] })
);
yield await_event(div, "animationend");
return await_event(div, "animationend");
}).then(() => {
// After the changed notifications, which will be dispatched in the order that
// the animations were seeked, we should get removal MutationRecords in order
// (div, div::before, div::after), childA, (childB, childB::before).
// Note: The animations targeting to the pseudo element are appended after
// the animations of its parent element.
divAnimations = [ ...divAnimations,
...divBeforeAnimations,
...divAfterAnimations ];
childBAnimations = [ ...childBAnimations, ...childBPseudoAnimations ];
assert_records(seekRecords.concat(
{ added: [], changed: [], removed: divAnimations },
{ added: [], changed: [], removed: childAAnimations },
{ added: [], changed: [], removed: childBAnimations }),
"records after finishing");
// After the changed notifications, which will be dispatched in the order that
// the animations were seeked, we should get removal MutationRecords in order
// (div, div::before, div::after), childA, (childB, childB::before).
// Note: The animations targeting to the pseudo element are appended after
// the animations of its parent element.
divAnimations = [ ...divAnimations,
...divBeforeAnimations,
...divAfterAnimations ];
childBAnimations = [ ...childBAnimations, ...childBPseudoAnimations ];
assert_records(seekRecords.concat(
{ added: [], changed: [], removed: divAnimations },
{ added: [], changed: [], removed: childAAnimations },
{ added: [], changed: [], removed: childBAnimations }),
"records after finishing");
// Clean up
div.classList.remove("before");
div.classList.remove("after");
div.style = "";
childA.remove();
childB.remove();
extraStyle.remove();
});
// Clean up
div.classList.remove("before");
div.classList.remove("after");
div.style = "";
childA.remove();
childB.remove();
extraStyle.remove();
});
}, "tree_ordering: subtree");
// Run the tests.
SimpleTest.requestLongerTimeout(2);
SimpleTest.waitForExplicitFinish();
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ set: [["dom.animations-api.pending-member.enabled", true]] }
).then(runAllAsyncTests).then(() => {
SimpleTest.finish();
}, aError => {
ok(false, "Something failed: " + aError);
).then(runTest).then(() => {
done();
});
</script>

Просмотреть файл

@ -36,10 +36,10 @@ Test chrome-only MutationObserver animation notifications (sync tests)
* it will raise an assertion.
*/
function setupSynchronousObserver(t, target, subtree) {
var observer = new MutationObserver(records => {
assert_unreached("Any MutationRecords should not be observed in this " +
"callback");
});
var observer = new MutationObserver(records => {
assert_unreached("Any MutationRecords should not be observed in this " +
"callback");
});
t.add_cleanup(() => {
observer.disconnect();
});

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/Flex.h"
#include "mozilla/dom/Grid.h"
#include "mozilla/gfx/Matrix.h"
#include "nsDOMAttributeMap.h"
@ -27,6 +28,7 @@
#include "nsIDOMNodeList.h"
#include "nsIDOMDocument.h"
#include "nsIContentIterator.h"
#include "nsFlexContainerFrame.h"
#include "nsFocusManager.h"
#include "nsFrameManager.h"
#include "nsILinkHandler.h"
@ -3707,6 +3709,23 @@ Element::RequestPointerLock(CallerType aCallerType)
OwnerDoc()->RequestPointerLock(this, aCallerType);
}
already_AddRefed<Flex>
Element::GetAsFlexContainer()
{
nsIFrame* frame = GetPrimaryFrame();
// We need the flex frame to compute additional info, and use
// that annotated version of the frame.
nsFlexContainerFrame* flexFrame =
nsFlexContainerFrame::GetFlexFrameWithComputedInfo(frame);
if (flexFrame) {
RefPtr<Flex> flex = new Flex(this, flexFrame);
return flex.forget();
}
return nullptr;
}
void
Element::GetGridFragments(nsTArray<RefPtr<Grid>>& aResult)
{

Просмотреть файл

@ -189,6 +189,7 @@ class Link;
class DOMRect;
class DOMRectList;
class DestinationInsertionPointList;
class Flex;
class Grid;
// IID for the dom::Element interface
@ -1308,6 +1309,7 @@ public:
0;
}
already_AddRefed<Flex> GetAsFlexContainer();
void GetGridFragments(nsTArray<RefPtr<Grid>>& aResult);
already_AddRefed<DOMMatrixReadOnly> GetTransformToAncestor(Element& aAncestor);

Просмотреть файл

@ -485,5 +485,5 @@ counterlist = GENERATED_FILES['UseCounterList.h']
counterlist.script = 'gen-usecounters.py:use_counter_list'
counterlist.inputs = ['UseCounters.conf']
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -63,7 +63,6 @@
#include "nsError.h"
#include "nsIDOMXULButtonElement.h"
#include "nsIDOMXULCheckboxElement.h"
#include "nsIDOMXULPopupElement.h"
// Event related includes
#include "nsIDOMEventTarget.h"
@ -194,8 +193,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULPopupElement, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
};
nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
@ -475,10 +472,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULCheckboxElement)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULPopupElement, nsIDOMXULPopupElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULPopupElement)
DOM_CLASSINFO_MAP_END
static_assert(MOZ_ARRAY_LENGTH(sClassInfoData) == eDOMClassInfoIDCount,
"The number of items in sClassInfoData doesn't match the "
"number of nsIDOMClassInfo ID's, this is bad! Fix it!");

Просмотреть файл

@ -28,7 +28,6 @@ enum nsDOMClassInfoID
eDOMClassInfo_XULLabeledControlElement_id,
eDOMClassInfo_XULButtonElement_id,
eDOMClassInfo_XULCheckboxElement_id,
eDOMClassInfo_XULPopupElement_id,
// This one better be the last one in this list
eDOMClassInfoIDCount

Просмотреть файл

@ -52,14 +52,10 @@ using mozilla::AutoJSContext;
} \
nsINode* node = content_; \
NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document"); \
if (doc) { \
doc->BindingManager()->func_ params_; \
} \
doc->BindingManager()->func_ params_; \
do { \
nsINode::nsSlots* slots = node->GetExistingSlots(); \
if (slots && !slots->mMutationObservers.IsEmpty()) { \
/* No need to explicitly notify the first observer first \
since that'll happen anyway. */ \
NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS( \
slots->mMutationObservers, nsIMutationObserver, 1, \
func_, params_); \
@ -86,8 +82,6 @@ using mozilla::AutoJSContext;
do { \
nsINode::nsSlots* slots = node->GetExistingSlots(); \
if (slots && !slots->mMutationObservers.IsEmpty()) { \
/* No need to explicitly notify the first observer first \
since that'll happen anyway. */ \
NS_OBSERVER_AUTO_ARRAY_NOTIFY_OBSERVERS_WITH_QI( \
slots->mMutationObservers, nsIMutationObserver, 1, \
nsIAnimationObserver, func_, params_); \

Просмотреть файл

@ -160,7 +160,7 @@ PYTHON_UNITTEST_MANIFESTS += [
'mozwebidlcodegen/test/python.ini',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
# Suppress warnings in third-party code.
CXXFLAGS += [

Просмотреть файл

@ -54,5 +54,5 @@ LOCAL_INCLUDES += [
'/js/xpconnect/wrappers',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

2
dom/cache/moz.build поставляемый
Просмотреть файл

@ -100,5 +100,5 @@ XPCSHELL_TESTS_MANIFESTS += [
'test/xpcshell/xpcshell.ini',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -189,7 +189,7 @@ SOURCES += [
]
# Suppress warnings from third-party code.
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
SOURCES['MurmurHash3.cpp'].flags += ['-Wno-implicit-fallthrough']
LOCAL_INCLUDES += [
@ -220,5 +220,5 @@ CXXFLAGS += CONFIG['TK_CFLAGS']
LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -157,5 +157,5 @@ LOCAL_INCLUDES += [
'/layout/xul/tree/',
]
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']

Просмотреть файл

@ -53,7 +53,7 @@ FINAL_LIBRARY = 'xul'
CXXFLAGS += CONFIG['TK_CFLAGS']
if CONFIG['GNU_CXX']:
if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
CXXFLAGS += ['-Wno-error=shadow']
BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']

59
dom/flex/Flex.cpp Normal file
Просмотреть файл

@ -0,0 +1,59 @@
/* -*- 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 "Flex.h"
#include "FlexLine.h"
#include "mozilla/dom/FlexBinding.h"
#include "nsFlexContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Flex, mParent, mLines)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Flex)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Flex)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Flex)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Flex::Flex(Element* aParent,
nsFlexContainerFrame* aFrame)
: mParent(aParent)
{
MOZ_ASSERT(aFrame,
"Should never be instantiated with a null nsFlexContainerFrame");
// Eagerly create property values from aFrame, because we're not
// going to keep it around.
const ComputedFlexContainerInfo* containerInfo =
aFrame->GetFlexContainerInfo();
MOZ_ASSERT(containerInfo, "Should only be passed a frame with info.");
mLines.SetLength(containerInfo->mLines.Length());
uint32_t index = 0;
for (auto&& l : containerInfo->mLines) {
FlexLine* line = new FlexLine(this, &l);
mLines.ElementAt(index) = line;
index++;
}
}
JSObject*
Flex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return FlexBinding::Wrap(aCx, this, aGivenProto);
}
void
Flex::GetLines(nsTArray<RefPtr<FlexLine>>& aResult)
{
aResult.AppendElements(mLines);
}
} // namespace dom
} // namespace mozilla

50
dom/flex/Flex.h Normal file
Просмотреть файл

@ -0,0 +1,50 @@
/* -*- 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_Flex_h
#define mozilla_dom_Flex_h
#include "mozilla/dom/Element.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
class nsFlexContainerFrame;
namespace mozilla {
namespace dom {
class FlexLine;
class Flex : public nsISupports
, public nsWrapperCache
{
public:
explicit Flex(Element* aParent, nsFlexContainerFrame* aFrame);
protected:
virtual ~Flex() = default;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Flex)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
Element* GetParentObject()
{
return mParent;
}
void GetLines(nsTArray<RefPtr<FlexLine>>& aResult);
protected:
nsCOMPtr<Element> mParent;
nsTArray<RefPtr<FlexLine>> mLines;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_Flex_h */

98
dom/flex/FlexItem.cpp Normal file
Просмотреть файл

@ -0,0 +1,98 @@
/* -*- 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 "FlexItem.h"
#include "mozilla/dom/FlexBinding.h"
#include "nsFlexContainerFrame.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexItem, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexItem)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexItem)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexItem)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
FlexItem::FlexItem(FlexLine* aParent,
const ComputedFlexItemInfo* aItem)
: mParent(aParent)
{
MOZ_ASSERT(aItem,
"Should never be instantiated with a null ComputedFlexLineInfo.");
// Eagerly copy values from aItem, because we're not
// going to keep it around.
mNode = aItem->mNode;
// Convert app unit sizes to css pixel sizes.
mMainBaseSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mMainBaseSize);
mMainDeltaSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mMainDeltaSize);
mMainMinSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mMainMinSize);
mMainMaxSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mMainMaxSize);
mCrossMinSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mCrossMinSize);
mCrossMaxSize = nsPresContext::AppUnitsToDoubleCSSPixels(
aItem->mCrossMaxSize);
}
JSObject*
FlexItem::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return FlexItemBinding::Wrap(aCx, this, aGivenProto);
}
nsINode*
FlexItem::GetNode() const
{
return mNode;
}
double
FlexItem::MainBaseSize() const
{
return mMainBaseSize;
}
double
FlexItem::MainDeltaSize() const
{
return mMainDeltaSize;
}
double
FlexItem::MainMinSize() const
{
return mMainMinSize;
}
double
FlexItem::MainMaxSize() const
{
return mMainMaxSize;
}
double
FlexItem::CrossMinSize() const
{
return mCrossMinSize;
}
double
FlexItem::CrossMaxSize() const
{
return mCrossMaxSize;
}
} // namespace dom
} // namespace mozilla

65
dom/flex/FlexItem.h Normal file
Просмотреть файл

@ -0,0 +1,65 @@
/* -*- 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_FlexItem_h
#define mozilla_dom_FlexItem_h
#include "mozilla/dom/FlexBinding.h"
#include "nsISupports.h"
#include "nsWrapperCache.h"
struct ComputedFlexItemInfo;
namespace mozilla {
namespace dom {
class FlexLine;
class FlexItem : public nsISupports
, public nsWrapperCache
{
public:
explicit FlexItem(FlexLine* aParent,
const ComputedFlexItemInfo* aItem);
protected:
virtual ~FlexItem() = default;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexItem)
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
FlexLine* GetParentObject()
{
return mParent;
}
nsINode* GetNode() const;
double MainBaseSize() const;
double MainDeltaSize() const;
double MainMinSize() const;
double MainMaxSize() const;
double CrossMinSize() const;
double CrossMaxSize() const;
protected:
RefPtr<FlexLine> mParent;
RefPtr<nsINode> mNode;
// These sizes are all CSS pixel units.
double mMainBaseSize;
double mMainDeltaSize;
double mMainMinSize;
double mMainMaxSize;
double mCrossMinSize;
double mCrossMaxSize;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_FlexItem_h */

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше