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

This commit is contained in:
Brindusan Cristian 2019-04-17 18:57:51 +03:00
Родитель 4cc7de3535 59ea5c03e6
Коммит 9d9534d1c9
121 изменённых файлов: 4995 добавлений и 2063 удалений

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

@ -342,6 +342,11 @@ void SessionAccessibility::ReplaceViewportCache(
auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
for (size_t i = 0; i < aAccessibles.Length(); i++) {
AccessibleWrap* acc = aAccessibles.ElementAt(i);
if (!acc) {
MOZ_ASSERT_UNREACHABLE("Updated accessible is gone.");
continue;
}
if (aData.Length() == aAccessibles.Length()) {
const BatchData& data = aData.ElementAt(i);
auto bundle = acc->ToBundle(
@ -363,6 +368,11 @@ void SessionAccessibility::ReplaceFocusPathCache(
auto infos = jni::ObjectArray::New<java::GeckoBundle>(aAccessibles.Length());
for (size_t i = 0; i < aAccessibles.Length(); i++) {
AccessibleWrap* acc = aAccessibles.ElementAt(i);
if (!acc) {
MOZ_ASSERT_UNREACHABLE("Updated accessible is gone.");
continue;
}
if (aData.Length() == aAccessibles.Length()) {
const BatchData& data = aData.ElementAt(i);
nsCOMPtr<nsIPersistentProperties> props =

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

@ -1009,7 +1009,11 @@ pref("browser.flash-protected-mode-flip.enable", false);
pref("browser.flash-protected-mode-flip.done", false);
// Dark in-content pages
#ifdef NIGHTLY_BUILD
pref("browser.in-content.dark-mode", true);
#else
pref("browser.in-content.dark-mode", false);
#endif
pref("dom.ipc.shims.enabledWarnings", false);

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

@ -4015,7 +4015,7 @@ const BrowserSearch = {
// browser's offered engines.
this._removeMaybeOfferedEngine(engineName);
break;
case "engine-current":
case "engine-default":
if (this._searchInitComplete) {
this._updateURLBarPlaceholder(engineName);
}

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

@ -392,7 +392,7 @@ add_task(async function cycleEngines() {
let promiseEngineChange = function(newEngineName) {
return new Promise(resolve => {
Services.obs.addObserver(function resolver(subj, topic, data) {
if (data != "engine-current") {
if (data != "engine-default") {
return;
}
subj.QueryInterface(Ci.nsISearchEngine);

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

@ -87,7 +87,7 @@ this.TopSitesFeed = class TopSitesFeed {
observe(subj, topic, data) {
// We should update the current top sites if the search engine has been changed since
// the search engine that gets filtered out of top sites has changed.
if (topic === "browser-search-engine-modified" && data === "engine-current" && this.store.getState().Prefs.values[NO_DEFAULT_SEARCH_TILE_EXP_PREF]) {
if (topic === "browser-search-engine-modified" && data === "engine-default" && this.store.getState().Prefs.values[NO_DEFAULT_SEARCH_TILE_EXP_PREF]) {
delete this._currentSearchHostname;
this._currentSearchHostname = getShortURLForCurrentSearch();
this.refresh({broadcast: true});

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

@ -1164,7 +1164,7 @@ describe("Top Sites Feed", () => {
it("should call refresh and set ._currentSearchHostname to the new engine hostname when the the default search engine has been set", () => {
sinon.stub(feed, "refresh");
sandbox.stub(global.Services.search, "defaultEngine").value({identifier: "ddg", searchForm: "duckduckgo.com"});
feed.observe(null, "browser-search-engine-modified", "engine-current");
feed.observe(null, "browser-search-engine-modified", "engine-default");
assert.equal(feed._currentSearchHostname, "duckduckgo");
assert.calledOnce(feed.refresh);
});

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

@ -260,18 +260,15 @@ var gSearchPane = {
case "engine-removed":
gSearchPane.remove(aEngine);
break;
case "engine-current":
case "engine-default":
// If the user is going through the drop down using up/down keys, the
// dropdown may still be open (eg. on Windows) when engine-current is
// dropdown may still be open (eg. on Windows) when engine-default is
// fired, so rebuilding the list unconditionally would get in the way.
let selectedEngine =
document.getElementById("defaultEngine").selectedItem.engine;
if (selectedEngine.name != aEngine.name)
gSearchPane.buildDefaultEngineDropDown();
break;
case "engine-default":
// Not relevant
break;
}
}
},

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

@ -366,7 +366,7 @@ class TelemetryHandler {
let payload = `${info.provider}.in-content:${info.type}:${info.code || "none"}`;
let histogram = Services.telemetry.getKeyedHistogramById(SEARCH_COUNTS_HISTOGRAM_KEY);
histogram.add(payload);
LOG(`SearchTelemetry::recordSearchURLTelemetry: ${payload} for ${url}`);
LOG(`SearchTelemetry: ${payload} for ${url}`);
}
/**
@ -490,7 +490,7 @@ class ContentHandler {
}
Services.telemetry.keyedScalarAdd(SEARCH_AD_CLICKS_SCALAR, info[0], 1);
LOG(`SearchTelemetry::recordSearchURLTelemetry: Counting ad click in page for ${info[0]} ${triggerURI.spec}`);
LOG(`SearchTelemetry: Counting ad click in page for ${info[0]} ${triggerURI.spec}`);
} catch (e) {
Cu.reportError(e);
}
@ -531,7 +531,7 @@ class ContentHandler {
}
Services.telemetry.keyedScalarAdd(SEARCH_WITH_ADS_SCALAR, item.info.provider, 1);
LOG(`SearchTelemetry::recordSearchURLTelemetry: Counting ads in page for ${item.info.provider} ${info.url}`);
LOG(`SearchTelemetry: Counting ads in page for ${item.info.provider} ${info.url}`);
}
}

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

@ -67,7 +67,7 @@ function promiseSetEngine() {
ok(engine, "Engine was added.");
ss.defaultEngine = engine;
break;
case "engine-current":
case "engine-default":
ok(ss.defaultEngine.name == "Bug 426329", "defaultEngine set");
searchBar = BrowserSearch.searchBar;
searchButton = searchBar.querySelector(".search-go-button");

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

@ -17,7 +17,7 @@ function observer(aSubject, aTopic, aData) {
if (gCurrentTest.added)
method = "added";
break;
case "engine-current":
case "engine-default":
if (gCurrentTest.current)
method = "current";
break;

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

@ -59,7 +59,7 @@ function test() {
Services.search.defaultEngine = engine;
break;
case "engine-current":
case "engine-default":
// We may be called again when resetting the engine at the end.
if (!calledTestTelemetry) {
is(Services.search.defaultEngine.name, "Foo", "Current engine is Foo");

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

@ -112,7 +112,7 @@ add_task(async function test_urlBarChangeEngine() {
function promisedefaultEngineChanged() {
return new Promise(resolve => {
function observer(aSub, aTopic, aData) {
if (aData == "engine-current") {
if (aData == "engine-default") {
Assert.equal(Services.search.defaultEngine.name, TEST_ENGINE_NAME, "defaultEngine set");
Services.obs.removeObserver(observer, "browser-search-engine-modified");
resolve();

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

@ -377,7 +377,7 @@ var tests = [
await new Promise(resolve => {
let observe = function(subject, topic, verb) {
info("browser-search-engine-modified: " + verb);
if (verb == "engine-current") {
if (verb == "engine-default") {
is(Services.search.defaultEngine.identifier, someOtherEngineID, "correct engine was switched to");
done();
}

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

@ -461,12 +461,10 @@ var ContentSearch = {
},
async _onObserve(data) {
if (data === "engine-current") {
if (data === "engine-default") {
let engine = await this._currentEngineObj();
this._broadcast("CurrentEngine", engine);
} else if (data !== "engine-default") {
// engine-default is always sent with engine-current and isn't otherwise
// relevant to content searches.
} else {
let state = await this.currentStateObj();
this._broadcast("CurrentState", state);
}

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

@ -77,14 +77,14 @@ add_task(async function SetDefaultEngine() {
let deferred = PromiseUtils.defer();
Services.obs.addObserver(function obs(subj, topic, data) {
info("Test observed " + data);
if (data == "engine-current") {
ok(true, "Test observed engine-current");
if (data == "engine-default") {
ok(true, "Test observed engine-default");
Services.obs.removeObserver(obs, "browser-search-engine-modified");
deferred.resolve();
}
}, "browser-search-engine-modified");
let searchPromise = waitForTestMsg(mm, "CurrentEngine");
info("Waiting for test to observe engine-current...");
info("Waiting for test to observe engine-default...");
await deferred.promise;
let msg = await searchPromise;
checkMsg(msg, {

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

@ -508,9 +508,8 @@ add_task(async function test_suggestion_rightclick() {
});
add_task(async function test_privateWindow() {
// Mock the search telemetry search provider info so that its
// recordSearchURLTelemetry() function adds the in-content SEARCH_COUNTS
// telemetry for our test engine.
// Override the search telemetry search provider info to
// count in-content SEARCH_COUNTs telemetry for our test engine.
SearchTelemetry.overrideSearchTelemetryForTests({
"example": {
"regexp": "^http://example\\.com/",

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

@ -88,7 +88,7 @@
/* Override styling that sets descriptions as grey */
#trackingGroup description.indent,
#trackingGroup .indent > description {
color: #000;
color: inherit;
}
[data-subcategory="trackingprotection"] {
@ -101,8 +101,9 @@
#trackingProtectionShield {
list-style-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg");
-moz-context-properties: fill;
fill: #737373;
-moz-context-properties: fill, fill-opacity;
fill: currentColor;
fill-opacity: 0.5;
width: 64px;
height: 64px;
margin-inline-end: 10px;
@ -112,7 +113,7 @@
border-radius: 4px;
margin: 3px 0;
padding: 9px;
border: 1px solid #D7D7DB;
border: 1px solid var(--in-content-border-color);
background-color: rgba(215, 215, 219, 0.2);
}

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

@ -126,45 +126,26 @@ with only_when(target_is_osx):
# MacOS SDK
# =========
js_option('--with-macos-sdk', env='MACOS_SDK_DIR', nargs=1,
help='Location of platform SDK to use')
option('--with-macos-sdk', env='MACOS_SDK_DIR', nargs=1,
help='Location of platform SDK to use')
@depends('--with-macos-sdk')
@depends_if('--with-macos-sdk')
@imports(_from='os.path', _import='isdir')
@imports(_from='biplist', _import='readPlist')
@imports('subprocess')
@imports('which')
@imports(_from='plistlib', _import='readPlist')
def macos_sdk(value):
sdk_min_version = Version('10.11')
sdk_max_version = Version('10.13')
sdk_max_version = Version('10.14')
sdk_path = None
if value:
sdk_path = value[0]
else:
try:
xcrun = which.which('xcrun')
args = [xcrun, '--sdk', 'macosx', '--show-sdk-path']
sdk_path = subprocess.check_output(args).strip()
except which.WhichError:
# On a Linux cross-compile, we don't have xcrun, so just leave
# the SDK unset if --with-macos-sdk isn't specified.
pass
if not sdk_path:
return
if not isdir(sdk_path):
if not isdir(value[0]):
die('SDK not found in %s. When using --with-macos-sdk, you must specify a '
'valid SDK. SDKs are installed when the optional cross-development '
'tools are selected during the Xcode/Developer Tools installation.'
% sdk_path)
obj = readPlist(os.path.join(sdk_path, 'SDKSettings.plist'))
% value[0])
obj = readPlist(os.path.join(value[0], 'SDKSettings.plist'))
if not obj:
die('Error parsing SDKSettings.plist in the SDK directory: %s' % sdk_path)
die('Error parsing SDKSettings.plist in the SDK directory: %s' % value[0])
if 'Version' not in obj:
die('Error finding Version information in SDKSettings.plist from the '
'SDK: %s' % sdk_path)
die('Error finding Version information in SDKSettings.plist from the SDK: %s' % value[0])
version = Version(obj['Version'])
if version < sdk_min_version:
die('SDK version "%s" is too old. Please upgrade to at least %s. '
@ -176,7 +157,7 @@ with only_when(target_is_osx):
'%s. You may need to point to it using --with-macos-sdk=<path> in '
'your mozconfig. Various SDK versions are available from '
'https://github.com/phracker/MacOSX-SDKs' % (version, sdk_max_version))
return sdk_path
return value[0]
set_config('MACOS_SDK_DIR', macos_sdk)

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

@ -106,6 +106,18 @@ declare module "debugger-html" {
this: Object
};
/**
* Original Frame
*
* @memberof types
* @static
*/
declare type OriginalFrame = {
displayName: string,
location?: SourceLocation,
thread?: string
};
/**
* why
* @memberof types

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

@ -122,11 +122,11 @@
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jest": "^21.15.1",
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-mozilla": "1.1.3",
"eslint-plugin-mozilla": "1.2.1",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-react": "^7.2.1",
"expect.js": "^0.3.1",
"flow-bin": "0.96.0",
"flow-bin": "0.97.0",
"glob": "^7.0.3",
"husky": "^1.0.1",
"jest": "^23.0.0",

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

@ -8,7 +8,13 @@ const {
workerUtils: { WorkerDispatcher }
} = require("devtools-utils");
import type { SourceLocation, Source, SourceId } from "../../../src/types";
import type {
OriginalFrame,
Range,
SourceLocation,
Source,
SourceId
} from "../../../src/types";
import type { SourceMapConsumer } from "source-map";
import type { locationOptions } from "./source-map";
@ -87,18 +93,7 @@ export const getGeneratedRangesForOriginal = async (
sourceId: SourceId,
url: string,
mergeUnmappedRegions?: boolean
): Promise<
Array<{
start: {
line: number,
column: number
},
end: {
line: number,
column: number
}
}>
> =>
): Promise<Range[]> =>
dispatcher.invoke(
"getGeneratedRangesForOriginal",
sourceId,
@ -108,8 +103,7 @@ export const getGeneratedRangesForOriginal = async (
export const getFileGeneratedRange = async (
originalSource: Source
): Promise<?{ start: any, end: any }> =>
dispatcher.invoke("getFileGeneratedRange", originalSource);
): Promise<Range> => dispatcher.invoke("getFileGeneratedRange", originalSource);
export const getLocationScopes = dispatcher.task("getLocationScopes");
@ -137,10 +131,8 @@ export const hasMappedSource = async (
export const getOriginalStackFrames = async (
generatedLocation: SourceLocation
): Promise<?Array<{
displayName: string,
location?: SourceLocation
}>> => dispatcher.invoke("getOriginalStackFrames", generatedLocation);
): Promise<?Array<OriginalFrame>> =>
dispatcher.invoke("getOriginalStackFrames", generatedLocation);
export {
originalToGeneratedId,

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

@ -4,7 +4,7 @@
// @flow
import type { SourceLocation } from "debugger-html";
import type { OriginalFrame, SourceLocation } from "debugger-html";
const { getWasmXScopes } = require("./wasmXScopes");
@ -12,10 +12,7 @@ const { getWasmXScopes } = require("./wasmXScopes");
// The function return null if not information was found.
async function getOriginalStackFrames(
generatedLocation: SourceLocation
): Promise<?Array<{
displayName: string,
location?: SourceLocation
}>> {
): Promise<?Array<OriginalFrame>> {
const wasmXScopes = await getWasmXScopes(generatedLocation.sourceId);
if (!wasmXScopes) {
return null;

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

@ -5,7 +5,7 @@
// @flow
/* eslint camelcase: 0*/
import type { SourceLocation, SourceId } from "debugger-html";
import type { OriginalFrame, SourceLocation, SourceId } from "debugger-html";
const { getSourceMap } = require("./sourceMapRequests");
const { generatedToOriginalId } = require("./index");
@ -153,12 +153,7 @@ class XScope {
this.xScope = xScopeData;
}
search(
generatedLocation: SourceLocation
): Array<{
displayName: string,
location?: SourceLocation
}> {
search(generatedLocation: SourceLocation): Array<OriginalFrame> {
const { code_section_offset, debug_info, sources, idIndex } = this.xScope;
const pc = generatedLocation.line - (code_section_offset || 0);
const scopes = filterScopes(debug_info, pc, null, idIndex);

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

@ -4,7 +4,10 @@
// @flow
import { isOriginalId, originalToGeneratedId } from "devtools-source-map";
import SourceMaps, {
isOriginalId,
originalToGeneratedId
} from "devtools-source-map";
import { uniqBy, zip } from "lodash";
import {
@ -16,6 +19,7 @@ import {
import type {
MappedLocation,
Range,
SourceLocation,
BreakpointPositions,
Context
@ -26,13 +30,11 @@ import {
type MemoizedAction
} from "../../utils/memoizableAction";
import typeof SourceMaps from "../../../packages/devtools-source-map/src";
// const requests = new Map();
async function mapLocations(
generatedLocations: SourceLocation[],
{ sourceMaps }: { sourceMaps: SourceMaps }
{ sourceMaps }: { sourceMaps: typeof SourceMaps }
) {
const originalLocations = await sourceMaps.getOriginalLocations(
generatedLocations
@ -82,7 +84,9 @@ async function _setBreakpointPositions(cx, sourceId, thunkArgs) {
let results = {};
if (isOriginalId(sourceId)) {
const ranges = await sourceMaps.getGeneratedRangesForOriginal(
// Explicitly typing ranges is required to work around the following issue
// https://github.com/facebook/flow/issues/5294
const ranges: Range[] = await sourceMaps.getGeneratedRangesForOriginal(
sourceId,
generatedSource.url,
true
@ -98,8 +102,10 @@ async function _setBreakpointPositions(cx, sourceId, thunkArgs) {
// and because we know we don't care about the end-line whitespace
// in this case.
if (range.end.column === Infinity) {
range.end.line += 1;
range.end.column = 0;
range.end = {
line: range.end.line + 1,
column: 0
};
}
const bps = await client.getBreakpointPositions(generatedSource, range);

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

@ -4,12 +4,14 @@
// @flow
import typeof SourceMaps from "devtools-source-map";
import type { Breakpoint } from "../../types";
export default function remapLocations(
breakpoints: Breakpoint[],
sourceId: string,
sourceMaps: Object
sourceMaps: SourceMaps
) {
const sourceBreakpoints: Promise<Breakpoint>[] = breakpoints.map(
async breakpoint => {

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

@ -16,11 +16,11 @@ import assert from "../../utils/assert";
import { findClosestFunction } from "../../utils/ast";
import { setSymbols } from "../sources/symbols";
import type { Frame, ThreadContext } from "../../types";
import type { Frame, OriginalFrame, ThreadContext } from "../../types";
import type { State } from "../../reducers/types";
import type { ThunkArgs } from "../types";
import { isGeneratedId } from "devtools-source-map";
import SourceMaps, { isGeneratedId } from "devtools-source-map";
function isFrameBlackboxed(state, frame) {
const source = getSource(state, frame.location.sourceId);
@ -37,7 +37,10 @@ function getSelectedFrameId(state, thread, frames) {
return selectedFrame && selectedFrame.id;
}
export function updateFrameLocation(frame: Frame, sourceMaps: any) {
export function updateFrameLocation(
frame: Frame,
sourceMaps: typeof SourceMaps
) {
if (frame.isOriginal) {
return Promise.resolve(frame);
}
@ -50,7 +53,7 @@ export function updateFrameLocation(frame: Frame, sourceMaps: any) {
function updateFrameLocations(
frames: Frame[],
sourceMaps: any
sourceMaps: typeof SourceMaps
): Promise<Frame[]> {
if (!frames || frames.length == 0) {
return Promise.resolve(frames);
@ -107,7 +110,7 @@ function isWasmOriginalSourceFrame(frame, getState: () => State): boolean {
async function expandFrames(
frames: Frame[],
sourceMaps: any,
sourceMaps: typeof SourceMaps,
getState: () => State
): Promise<Frame[]> {
const result = [];
@ -117,9 +120,9 @@ async function expandFrames(
result.push(frame);
continue;
}
const originalFrames = await sourceMaps.getOriginalStackFrames(
frame.generatedLocation
);
const originalFrames: ?Array<
OriginalFrame
> = await sourceMaps.getOriginalStackFrames(frame.generatedLocation);
if (!originalFrames) {
result.push(frame);
continue;
@ -133,6 +136,10 @@ async function expandFrames(
};
originalFrames.forEach((originalFrame, j) => {
if (!originalFrame.location || !originalFrame.thread) {
return;
}
// Keep outer most frame with true actor ID, and generate uniquie
// one for the nested frames.
const id = j == 0 ? frame.id : `${frame.id}-originalFrame${j}`;

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

@ -101,8 +101,10 @@ function loadSourceMap(cx: Context, sourceId: SourceId) {
let urls = null;
try {
const urlInfo = { ...source };
if (!urlInfo.url) {
// Unable to correctly type the result of a spread on a union type.
// See https://github.com/facebook/flow/pull/7298
const urlInfo: Source = { ...(source: any) };
if (!urlInfo.url && typeof urlInfo.introductionUrl === "string") {
// If the source was dynamically generated (via eval, dynamically
// created script elements, and so forth), it won't have a URL, so that
// it is not collapsed into other sources from the same place. The

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

@ -3,7 +3,7 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// @flow
import { generatedToOriginalId } from "devtools-source-map";
import SourceMaps, { generatedToOriginalId } from "devtools-source-map";
import assert from "../../utils/assert";
import { recordEvent } from "../../utils/telemetry";
@ -29,7 +29,7 @@ import { selectSource } from "./select";
import type { JsSource, Source, Context } from "../../types";
export async function prettyPrintSource(
sourceMaps: any,
sourceMaps: typeof SourceMaps,
prettySource: Source,
generatedSource: any
) {

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

@ -4,6 +4,7 @@
// @flow
import typeof SourceMaps from "devtools-source-map";
import type { WorkerList, MainThread, Context, ThreadId } from "../../types";
import type { State } from "../../reducers/types";
import type { MatchedLocations } from "../../reducers/file-search";
@ -34,7 +35,7 @@ export type ThunkArgs = {
dispatch: (action: any) => Promise<any>,
getState: () => State,
client: typeof clientCommands,
sourceMaps: any,
sourceMaps: SourceMaps,
panel: Panel
};

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

@ -152,6 +152,7 @@ class App extends Component<Props, State> {
closeQuickOpen,
quickOpenEnabled
} = this.props;
const { shortcutsModalEnabled } = this.state;
if (activeSearch) {
e.preventDefault();
@ -162,6 +163,10 @@ class App extends Component<Props, State> {
e.preventDefault();
closeQuickOpen();
}
if (shortcutsModalEnabled) {
this.toggleShortcutsModal();
}
};
onCommandSlash = () => {

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

@ -18,18 +18,27 @@
box-sizing: border-box;
}
.source-footer .commands {
.source-footer-start {
display: flex;
align-items: center;
justify-self: start;
}
.source-footer-end {
display: flex;
margin-left: auto;
}
.source-footer .commands * {
-moz-user-select: none;
user-select: none;
}
.source-footer > .commands > .action {
.source-footer > .source-footer-start > .commands {
display: flex;
}
.source-footer > .source-footer-start > .commands > .action {
display: flex;
justify-content: center;
align-items: center;
@ -39,25 +48,33 @@
padding: 4px 6px;
}
.source-footer > .commands > button.action:hover {
.source-footer > .source-footer-start > .commands > button.action:hover {
background: var(--theme-toolbar-background-hover);
}
:root.theme-dark .source-footer > .commands > .action {
:root.theme-dark .source-footer > .source-footer-start > .commands > .action {
fill: var(--theme-body-color);
}
:root.theme-dark .source-footer > .commands > .action:hover {
:root.theme-dark
.source-footer
> .source-footer-start
> .commands
> .action:hover {
fill: var(--theme-selection-color);
}
.source-footer > .commands > div.loader {
.source-footer > .source-footer-start > .commands > div.loader {
vertical-align: top;
width: 20px;
margin: 0 4px;
}
.source-footer > .commands > .blackboxed > .img.blackBox {
.source-footer
> .source-footer-start
> .commands
> .blackboxed
> .img.blackBox {
background-color: var(--theme-icon-checked-color);
}
@ -65,7 +82,6 @@
.source-footer .cursor-position {
color: var(--theme-body-color);
padding-right: 2.5px;
margin-left: auto;
}
.source-footer .mapped-source {

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

@ -166,7 +166,6 @@ class SourceFooter extends PureComponent<Props, State> {
return (
<PaneToggleButton
position="end"
key="toggle"
collapsed={this.props.endPanelCollapsed}
horizontal={this.props.horizontal}
@ -249,10 +248,12 @@ class SourceFooter extends PureComponent<Props, State> {
render() {
return (
<div className="source-footer">
{this.renderCommands()}
{this.renderSourceSummary()}
{this.renderCursorPosition()}
{this.renderToggleButton()}
<div className="source-footer-start">{this.renderCommands()}</div>
<div className="source-footer-end">
{this.renderSourceSummary()}
{this.renderCursorPosition()}
{this.renderToggleButton()}
</div>
</div>
);
}

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

@ -5,17 +5,24 @@ exports[`SourceFooter Component default case should render 1`] = `
className="source-footer"
>
<div
className="cursor-position"
title="(Line 1, column 1)"
>
(1, 1)
</div>
<PaneToggleButton
collapsed={false}
horizontal={false}
key="toggle"
position="end"
className="source-footer-start"
/>
<div
className="source-footer-end"
>
<div
className="cursor-position"
title="(Line 1, column 1)"
>
(1, 1)
</div>
<PaneToggleButton
collapsed={false}
horizontal={false}
key="toggle"
position="start"
/>
</div>
</div>
`;
@ -24,16 +31,23 @@ exports[`SourceFooter Component move cursor should render new cursor position 1`
className="source-footer"
>
<div
className="cursor-position"
title="(Line 6, column 11)"
>
(6, 11)
</div>
<PaneToggleButton
collapsed={false}
horizontal={false}
key="toggle"
position="end"
className="source-footer-start"
/>
<div
className="source-footer-end"
>
<div
className="cursor-position"
title="(Line 6, column 11)"
>
(6, 11)
</div>
<PaneToggleButton
collapsed={false}
horizontal={false}
key="toggle"
position="start"
/>
</div>
</div>
`;

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

@ -71,10 +71,12 @@ type GotoLocationType = {
column?: number
};
const maxResults = 100;
function filter(values, query) {
return fuzzyAldrin.filter(values, query, {
key: "value",
maxResults: 1000
maxResults: maxResults
});
}
@ -84,6 +86,13 @@ export class QuickOpenModal extends Component<Props, State> {
this.state = { results: null, selectedIndex: 0 };
}
setResults(results: ?Array<QuickOpenResult>) {
if (results) {
results = results.slice(0, maxResults);
}
this.setState({ results });
}
componentDidMount() {
const { query, shortcutsModalEnabled, toggleShortcutsModal } = this.props;
@ -123,7 +132,7 @@ export class QuickOpenModal extends Component<Props, State> {
const { sources } = this.props;
const results =
query == "" ? sources : filter(sources, this.dropGoto(query));
return this.setState({ results });
return this.setResults(results);
};
searchSymbols = (query: string) => {
@ -135,18 +144,18 @@ export class QuickOpenModal extends Component<Props, State> {
results = results.filter(result => result.title !== "anonymous");
if (query === "@" || query === "#") {
return this.setState({ results });
return this.setResults(results);
}
this.setState({ results: filter(results, query.slice(1)) });
results = filter(results, query.slice(1));
return this.setResults(results);
};
searchShortcuts = (query: string) => {
const results = formatShortcutResults();
if (query == "?") {
this.setState({ results });
this.setResults(results);
} else {
this.setState({ results: filter(results, query.slice(1)) });
this.setResults(filter(results, query.slice(1)));
}
};
@ -154,12 +163,9 @@ export class QuickOpenModal extends Component<Props, State> {
const { tabs, sources } = this.props;
if (tabs.length > 0) {
const tabUrls = tabs.map((tab: Tab) => tab.url);
this.setState({
results: sources.filter(source => tabUrls.includes(source.url))
});
this.setResults(sources.filter(source => tabUrls.includes(source.url)));
} else {
this.setState({ results: sources.slice(0, 100) });
this.setResults(sources);
}
};
@ -376,8 +382,7 @@ export class QuickOpenModal extends Component<Props, State> {
if (!enabled) {
return null;
}
const newResults = results && results.slice(0, 100);
const items = this.highlightMatching(query, newResults || []);
const items = this.highlightMatching(query, results || []);
const expanded = !!items && items.length > 0;
return (
@ -400,7 +405,7 @@ export class QuickOpenModal extends Component<Props, State> {
}
{...(this.isSourceSearch() ? { size: "big" } : {})}
/>
{newResults && (
{results && (
<ResultList
key="results"
items={items}

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

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
.breakpoints-pane > ._content {
overflow-x: auto;
}
.breakpoints-toggle {
margin: 2px 3px;
}

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

@ -49,6 +49,7 @@
/* TODO: add normalize */
margin: 0;
padding: 4px 0px;
overflow-x: auto;
}
.expression-input-container {

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

@ -3,7 +3,8 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
.secondary-panes {
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
display: flex;
flex-direction: column;
flex: 1;

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

@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
.xhr-breakpoints-pane ._content {
overflow-x: auto;
}
.xhr-input-container {
display: flex;
border: 1px solid transparent;

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

@ -211,7 +211,7 @@ describe("QuickOpenModal", () => {
wrapper.find("input").simulate("change", { target: { value: "somefil" } });
expect(filter).toHaveBeenCalledWith([], "somefil", {
key: "value",
maxResults: 1000
maxResults: 100
});
});
@ -232,7 +232,7 @@ describe("QuickOpenModal", () => {
.simulate("change", { target: { value: "somefil:33" } });
expect(filter).toHaveBeenCalledWith([], "somefil", {
key: "value",
maxResults: 1000
maxResults: 100
});
});
@ -259,7 +259,7 @@ describe("QuickOpenModal", () => {
expect(filter).toHaveBeenCalledWith([], "someFunc", {
key: "value",
maxResults: 1000
maxResults: 100
});
});

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

@ -235,6 +235,12 @@ export type ChromeFrame = {
location: ?SourceLocation
};
export type OriginalFrame = {
displayName: string,
location?: SourceLocation,
thread: string
};
/**
* ContextMenuItem
*

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

@ -10,7 +10,10 @@ import ReactDOM from "react-dom";
const { Provider } = require("react-redux");
import { isFirefoxPanel, isDevelopment, isTesting } from "devtools-environment";
import { startSourceMapWorker, stopSourceMapWorker } from "devtools-source-map";
import SourceMaps, {
startSourceMapWorker,
stopSourceMapWorker
} from "devtools-source-map";
import * as search from "../workers/search";
import * as prettyPrint from "../workers/pretty-print";
import * as parser from "../workers/parser";
@ -22,7 +25,6 @@ import App from "../components/App";
import { asyncStore, prefs } from "./prefs";
import type { Panel } from "../client/firefox/types";
import typeof SourceMaps from "../../packages/devtools-source-map/src";
function renderPanel(component, store) {
const root = document.createElement("div");
@ -42,7 +44,7 @@ function renderPanel(component, store) {
export function bootstrapStore(
client: any,
sourceMaps: SourceMaps,
sourceMaps: typeof SourceMaps,
panel: Panel,
initialState: Object
) {

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

@ -4,6 +4,8 @@
// @flow
import typeof SourceMaps from "devtools-source-map";
import type { BindingLocationType, BindingType } from "../../../workers/parser";
import { positionCmp } from "./positionCmp";
import { filterSortedArray } from "./filtering";
@ -34,7 +36,7 @@ export async function originalRangeStartsInside(
start: SourceLocation,
end: SourceLocation
},
sourceMaps: any
sourceMaps: SourceMaps
) {
const endPosition = await sourceMaps.getGeneratedLocation(end, source);
const startPosition = await sourceMaps.getGeneratedLocation(start, source);
@ -58,11 +60,11 @@ export async function getApplicableBindingsForOriginalPosition(
},
bindingType: BindingType,
locationType: BindingLocationType,
sourceMaps: any
sourceMaps: SourceMaps
): Promise<Array<ApplicableBinding>> {
const ranges = await sourceMaps.getGeneratedRanges(start, source);
const resultRanges = ranges.map(mapRange => ({
const resultRanges: GeneratedRange[] = ranges.map(mapRange => ({
start: {
line: mapRange.line,
column: mapRange.columnStart
@ -91,8 +93,10 @@ export async function getApplicableBindingsForOriginalPosition(
mappingContains(range, { start: startPosition, end: startPosition }) &&
positionCmp(range.end, endPosition) < 0
) {
range.end.line = endPosition.line;
range.end.column = endPosition.column;
range.end = {
line: endPosition.line,
column: endPosition.column
};
break;
}
}

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

@ -4,6 +4,8 @@
// @flow
import typeof SourceMaps from "devtools-source-map";
import {
getScopes,
type SourceScope,
@ -200,7 +202,7 @@ function hasLineMappings(ranges) {
function batchScopeMappings(
originalAstScopes: Array<SourceScope>,
source: Source,
sourceMaps: any
sourceMaps: SourceMaps
) {
const precalculatedRanges = new Map();
const precalculatedLocations = new Map();

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

@ -4,6 +4,8 @@
// @flow
import typeof SourceMaps from "devtools-source-map";
import { locColumn } from "./locColumn";
import { positionCmp } from "./positionCmp";
import { filterSortedArray } from "./filtering";
@ -34,7 +36,7 @@ export async function loadRangeMetadata(
source: Source,
frame: Frame,
originalAstScopes: Array<SourceScope>,
sourceMaps: any
sourceMaps: SourceMaps
): Promise<Array<MappedOriginalRange>> {
const originalRanges: Array<
SourceOriginalRange

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

@ -4,17 +4,16 @@
// @flow
import { isOriginalId } from "devtools-source-map";
import SourceMaps, { isOriginalId } from "devtools-source-map";
import { getSource } from "../selectors";
import type { SourceLocation, MappedLocation, Source } from "../types";
import typeof SourceMaps from "../../packages/devtools-source-map/src";
export async function getGeneratedLocation(
state: Object,
source: Source,
location: SourceLocation,
sourceMaps: Object
sourceMaps: typeof SourceMaps
): Promise<SourceLocation> {
if (!isOriginalId(location.sourceId)) {
return location;
@ -40,7 +39,7 @@ export async function getGeneratedLocation(
export async function getOriginalLocation(
generatedLocation: SourceLocation,
sourceMaps: SourceMaps
sourceMaps: typeof SourceMaps
) {
if (isOriginalId(generatedLocation.sourceId)) {
return location;
@ -51,7 +50,7 @@ export async function getOriginalLocation(
export async function getMappedLocation(
state: Object,
sourceMaps: Object,
sourceMaps: typeof SourceMaps,
location: SourceLocation
): Promise<MappedLocation> {
const source = getSource(state, location.sourceId);
@ -72,8 +71,7 @@ export async function getMappedLocation(
const generatedLocation = location;
const originalLocation = await sourceMaps.getOriginalLocation(
generatedLocation,
source
generatedLocation
);
return { location: originalLocation, generatedLocation };
@ -81,7 +79,7 @@ export async function getMappedLocation(
export async function mapLocation(
state: Object,
sourceMaps: Object,
sourceMaps: typeof SourceMaps,
location: SourceLocation
): Promise<SourceLocation> {
const source = getSource(state, location.sourceId);
@ -94,7 +92,7 @@ export async function mapLocation(
return getGeneratedLocation(state, source, location, sourceMaps);
}
return sourceMaps.getOriginalLocation(location, source);
return sourceMaps.getOriginalLocation(location);
}
export function isOriginalSource(source: ?Source) {

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

@ -48,7 +48,8 @@ function findOrCreateNode(
part: string,
index: number,
url: Object,
debuggeeHost: ?string
debuggeeHost: ?string,
source: Source
): TreeDirectory {
const addedPartIsFile = partIsFile(index, parts, url);
@ -69,7 +70,12 @@ function findOrCreateNode(
// if we have a naming conflict, we'll create a new node
if (child.type === "source" || (!childIsFile && addedPartIsFile)) {
return createNodeInTree(part, path, subTree, childIndex);
// pass true to findNodeInContents to sort node by url
const { index: insertIndex } = findNodeInContents(
subTree,
createTreeNodeMatcher(part, !addedPartIsFile, debuggeeHost, source, true)
);
return createNodeInTree(part, path, subTree, insertIndex);
}
// if there is no naming conflict, we can traverse into the child
@ -83,7 +89,8 @@ function findOrCreateNode(
function traverseTree(
url: ParsedURL,
tree: TreeDirectory,
debuggeeHost: ?string
debuggeeHost: ?string,
source: Source
): TreeNode {
const parts = url.path.split("/").filter(p => p !== "");
parts.unshift(url.group);
@ -99,7 +106,8 @@ function traverseTree(
part,
index,
url,
debuggeeHostIfRoot
debuggeeHostIfRoot,
source
);
}, tree);
}
@ -165,7 +173,7 @@ export function addToTree(
return;
}
const finalNode = traverseTree(url, tree, debuggeeHost);
const finalNode = traverseTree(url, tree, debuggeeHost, source);
// $FlowIgnore
finalNode.contents = addSourceToNode(finalNode, url, source);

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

@ -10,6 +10,8 @@ import { nodeHasChildren } from "./utils";
import type { TreeNode } from "./types";
import type { Source } from "../../types";
/*
* Gets domain from url (without www prefix)
*/
@ -94,7 +96,9 @@ function createTreeNodeMatcherWithDebuggeeHost(
function createTreeNodeMatcherWithNameAndOther(
part: string,
isDir: boolean,
debuggeeHost: ?string
debuggeeHost: ?string,
source?: Source,
sortByUrl?: boolean
): FindNodeInContentsMatcher {
return (node: TreeNode) => {
if (node.name === IndexName) {
@ -109,6 +113,9 @@ function createTreeNodeMatcherWithNameAndOther(
} else if (!nodeIsDir && isDir) {
return 1;
}
if (sortByUrl && node.type === "source" && source) {
return node.contents.url.localeCompare(source.url);
}
return node.name.localeCompare(part);
};
@ -125,7 +132,9 @@ function createTreeNodeMatcherWithNameAndOther(
export function createTreeNodeMatcher(
part: string,
isDir: boolean,
debuggeeHost: ?string
debuggeeHost: ?string,
source?: Source,
sortByUrl?: boolean
): FindNodeInContentsMatcher {
if (part === IndexName) {
// Specialied matcher, when we are looking for "(index)" position.
@ -138,5 +147,11 @@ export function createTreeNodeMatcher(
}
// Rest of the cases, without mentioned above.
return createTreeNodeMatcherWithNameAndOther(part, isDir, debuggeeHost);
return createTreeNodeMatcherWithNameAndOther(
part,
isDir,
debuggeeHost,
source,
sortByUrl
);
}

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

@ -27,9 +27,14 @@ add_task(async function() {
const labels = [getLabel(dbg, 4), getLabel(dbg, 3)];
is(
labels.includes("simple1.js?x=1") && labels.includes("simple1.js?x=2"),
true,
"simple1.js?x=1 and simple2.jsx=2 exist"
getLabel(dbg, 3),
"simple1.js?x=1",
"simple1.js?x=1 exists"
);
is(
getLabel(dbg, 4),
"simple1.js?x=2",
"simple1.js?x=2 exists"
);
const source = findSource(dbg, "simple1.js?x=1");

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

@ -7,8 +7,8 @@
"description": "Network monitor in developer tools",
"dependencies": {
"babel-plugin-transform-flow-strip-types": "^6.22.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"codemirror": "^5.24.2",
"devtools-config": "=0.0.12",
"devtools-contextmenu": "=0.0.3",
@ -25,6 +25,8 @@
"reselect": "^3.0.1"
},
"scripts": {
"start": "node bin/dev-server"
}
"start": "node bin/dev-server",
"test": "jest"
},
"devDependencies": {}
}

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

@ -6,5 +6,8 @@
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js"
"extends": "../../../.eslintrc.mochitests.js",
"env": {
"jest": true
},
};

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

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { Sort, sortReducer} = require("../../src/reducers/sort");
const { SORT_BY } = require("../../src/constants");
describe("sorting reducer", () => {
it("it should sort by sort type", () => {
const initialState = new Sort();
const action = {
type: SORT_BY,
sortType: "TimeWhen",
};
const expectedState = {
type: "TimeWhen",
ascending: true,
};
expect(expectedState).toEqual(sortReducer(initialState, action));
});
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,9 +1,14 @@
const {AddonTestUtils} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm");
const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
const kSearchEngineID = "test_urifixup_search_engine";
const kSearchEngineURL = "http://www.example.org/?search={searchTerms}";
const kForceHostLookup = "browser.fixup.dns_first_for_single_words";
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
// TODO(bug 1522134), this test should also use
// combinations of the following flags.
var flagInputs = [
@ -465,7 +470,7 @@ var testcases = [ {
},
];
if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
if (AppConstants.platform == "win") {
testcases.push({
input: "C:\\some\\file.txt",
fixedURI: "file:///C:/some/file.txt",
@ -494,10 +499,6 @@ function sanitize(input) {
return input.replace(/\r|\n/g, "").trim();
}
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
add_task(async function setup() {
var prefList = ["browser.fixup.typo.scheme", "keyword.enabled",
"browser.fixup.domainwhitelist.whitelisted"];

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

@ -464,7 +464,7 @@ nsFocusManager::ElementIsFocusable(Element* aElement, uint32_t aFlags,
bool* aIsFocusable) {
NS_ENSURE_TRUE(aElement, NS_ERROR_INVALID_ARG);
*aIsFocusable = CheckIfFocusable(aElement, aFlags) != nullptr;
*aIsFocusable = FlushAndCheckIfFocusable(aElement, aFlags) != nullptr;
return NS_OK;
}
@ -1123,7 +1123,8 @@ void nsFocusManager::ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow,
void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags,
bool aFocusChanged, bool aAdjustWidget) {
// if the element is not focusable, just return and leave the focus as is
RefPtr<Element> elementToFocus = CheckIfFocusable(aNewContent, aFlags);
RefPtr<Element> elementToFocus =
FlushAndCheckIfFocusable(aNewContent, aFlags);
if (!elementToFocus) {
return;
}
@ -1459,16 +1460,10 @@ bool nsFocusManager::IsNonFocusableRoot(nsIContent* aContent) {
nsContentUtils::IsUserFocusIgnored(aContent));
}
Element* nsFocusManager::CheckIfFocusable(Element* aElement, uint32_t aFlags) {
Element* nsFocusManager::FlushAndCheckIfFocusable(Element* aElement,
uint32_t aFlags) {
if (!aElement) return nullptr;
// this is a special case for some XUL elements or input number, where an
// anonymous child is actually focusable and not the element itself.
RefPtr<Element> redirectedFocus = GetRedirectedFocus(aElement);
if (redirectedFocus) {
return CheckIfFocusable(redirectedFocus, aFlags);
}
nsCOMPtr<Document> doc = aElement->GetComposedDoc();
// can't focus elements that are not in documents
if (!doc) {
@ -1481,6 +1476,13 @@ Element* nsFocusManager::CheckIfFocusable(Element* aElement, uint32_t aFlags) {
mEventHandlingNeedsFlush = false;
doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
// this is a special case for some XUL elements or input number, where an
// anonymous child is actually focusable and not the element itself.
RefPtr<Element> redirectedFocus = GetRedirectedFocus(aElement);
if (redirectedFocus) {
return FlushAndCheckIfFocusable(redirectedFocus, aFlags);
}
PresShell* presShell = doc->GetPresShell();
if (!presShell) {
return nullptr;
@ -1749,7 +1751,7 @@ void nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow, Element* aElement,
// if the window isn't visible, for instance because it is a hidden tab,
// update the current focus and scroll it into view but don't do anything
// else
if (CheckIfFocusable(aElement, aFlags)) {
if (FlushAndCheckIfFocusable(aElement, aFlags)) {
aWindow->SetFocusedElement(aElement, focusMethod);
if (aFocusChanged) {
ScrollIntoView(presShell, aElement, aFlags);
@ -1829,7 +1831,7 @@ void nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow, Element* aElement,
// check to ensure that the element is still focusable, and that nothing
// else was focused during the events above.
if (CheckIfFocusable(aElement, aFlags) && mFocusedWindow == aWindow &&
if (FlushAndCheckIfFocusable(aElement, aFlags) && mFocusedWindow == aWindow &&
mFocusedElement == nullptr) {
mFocusedElement = aElement;
@ -2992,15 +2994,6 @@ static nsIContent* FindOwner(nsIContent* aContent) {
nsIContent* currentContent = aContent;
while (currentContent) {
nsIContent* parent = currentContent->GetFlattenedTreeParent();
if (!parent) {
// Document root
Document* doc = currentContent->GetUncomposedDoc();
if (doc && doc->GetRootElement() == currentContent) {
return currentContent;
}
break;
}
// Shadow host / Slot
if (IsHostOrSlot(parent)) {
@ -3258,12 +3251,9 @@ nsresult nsFocusManager::GetNextTabbableContent(
}
}
// If aStartContent is not in a scope owned by the root element
// (i.e. aStartContent is already in shadow DOM),
// search from scope including aStartContent
nsIContent* rootElement = aRootContent->OwnerDoc()->GetRootElement();
nsIContent* owner = FindOwner(aStartContent);
if (owner && rootElement != owner) {
// If aStartContent is in a scope owned by Shadow DOM search from scope
// including aStartContent
if (nsIContent* owner = FindOwner(aStartContent)) {
nsIContent* contentToFocus = GetNextTabbableContentInAncestorScopes(
owner, &aStartContent, aOriginalStartContent, aForward,
&aCurrentTabIndex, aIgnoreTabIndex, aForDocumentNavigation);
@ -3277,8 +3267,8 @@ nsresult nsFocusManager::GetNextTabbableContent(
// We need to continue searching in light DOM, starting at the top level
// shadow host in light DOM (updated aStartContent) and its tabindex
// (updated aCurrentTabIndex).
MOZ_ASSERT(FindOwner(aStartContent) == rootElement,
"aStartContent should be owned by the root element at this point");
MOZ_ASSERT(!FindOwner(aStartContent),
"aStartContent should not be owned by Shadow DOM at this point");
nsPresContext* presContext = aPresShell->GetPresContext();
@ -3437,7 +3427,7 @@ nsresult nsFocusManager::GetNextTabbableContent(
// append ELEMENT to NAVIGATION-ORDER."
// and later in "For each element ELEMENT in NAVIGATION-ORDER: "
// hosts and slots are handled before other elements.
if (currentContent && IsHostOrSlot(currentContent)) {
if (IsHostOrSlot(currentContent)) {
bool focusableHostSlot;
int32_t tabIndex =
HostOrSlotTabIndexValue(currentContent, &focusableHostSlot);
@ -3782,7 +3772,8 @@ nsresult nsFocusManager::FocusFirst(Element* aRootElement,
if (aRootElement->GetAttr(kNameSpaceID_None,
nsGkAtoms::retargetdocumentfocus, retarget)) {
nsCOMPtr<Element> element = doc->GetElementById(retarget);
nsCOMPtr<nsIContent> retargetElement = CheckIfFocusable(element, 0);
nsCOMPtr<nsIContent> retargetElement =
FlushAndCheckIfFocusable(element, 0);
if (retargetElement) {
retargetElement.forget(aNextContent);
return NS_OK;

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

@ -258,19 +258,21 @@ class nsFocusManager final : public nsIFocusManager,
bool IsNonFocusableRoot(nsIContent* aContent);
/**
* Checks and returns aContent if it may be focused, another content node if
* First flushes the pending notifications to ensure the PresShell and frames
* are updated.
* Checks and returns aElement if it may be focused, another element node if
* the focus should be retargeted at another node, or null if the node
* cannot be focused. aFlags are the flags passed to SetFocus and similar
* methods.
*
* An element is focusable if it is in a document, the document isn't in
* print preview mode and the element has an nsIFrame where the
* CheckIfFocusable method returns true. For <area> elements, there is no
* IsFocusable method returns true. For <area> elements, there is no
* frame, so only the IsFocusable method on the content node must be
* true.
*/
mozilla::dom::Element* CheckIfFocusable(mozilla::dom::Element* aContent,
uint32_t aFlags);
mozilla::dom::Element* FlushAndCheckIfFocusable(
mozilla::dom::Element* aElement, uint32_t aFlags);
/**
* Blurs the currently focused element. Returns false if another element was

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

@ -2793,12 +2793,16 @@ class LocalizationHandler : public PromiseNativeHandler {
l10nData[i].mAttributes;
if (!attributes.IsNull()) {
for (size_t j = 0; j < attributes.Value().Length(); ++j) {
// Use SetAttribute here to validate the attribute name!
elem->SetAttribute(attributes.Value()[j].mName,
attributes.Value()[j].mValue, rv);
if (rv.Failed()) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
nsString& name = attributes.Value()[j].mName;
nsString& value = attributes.Value()[j].mValue;
RefPtr<nsAtom> nameAtom = NS_Atomize(name);
if (!elem->AttrValueIs(kNameSpaceID_None, nameAtom, value,
eCaseMatters)) {
rv = elem->SetAttr(kNameSpaceID_None, nameAtom, value, true);
if (rv.Failed()) {
mReturnValuePromise->MaybeRejectWithUndefined();
return;
}
}
}
}

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

@ -1768,7 +1768,13 @@ bool InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData) {
uint32_t(idleDuration.ToSeconds() / duration.ToSeconds() * 100);
Telemetry::Accumulate(Telemetry::GC_SLICE_DURING_IDLE, percent);
}
return true;
// If we didn't use the whole budget, we're past the foreground sweeping slice
// and will need to wait for the background tasks to finish, or we're at the
// last slice. Return value on the latter case doesn't matter, and on the
// former we want to wait a bit before polling again.
// Returning false makes IdleTaskRunner postpone the next call a bit.
return int64_t(sliceDuration.ToMilliseconds()) >= budget;
}
// static

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

@ -620,7 +620,7 @@ skip-if = toolkit == 'android'
[test_bug1406102.html]
[test_bug1421568.html]
[test_bug1453693.html]
skip-if = os == "mac"
skip-if = os == "mac" # Different tab focus behavior on mac
[test_bug1472427.html]
[test_bug1499169.html]
skip-if = toolkit == 'android' # Timeouts on android due to page closing issues with embedded pdf
@ -668,6 +668,8 @@ skip-if = (toolkit == 'android') # Android: Bug 775227
skip-if = (toolkit == 'android') # Android: Bug 1465387
[test_find_nac.html]
skip-if = (toolkit == 'android') # Android: Bug 1465387
[test_focus_shadow_dom_root.html]
skip-if = os == "mac" # Different tab focus behavior on mac
[test_getAttribute_after_createAttribute.html]
[test_getElementById.html]
[test_getTranslationNodes.html]

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

@ -0,0 +1,36 @@
<!doctype html>
<title>Test for bug 1544826</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<div id="host"><a href="#" id="slotted">This is focusable too</a></div>
<script>
const host = document.getElementById("host");
const shadow = host.attachShadow({ mode: "open" });
shadow.innerHTML = `
<a id="shadow-1" href="#">This is focusable</a>
<slot></slot>
<a id="shadow-2" href="#">So is this</a>
`;
document.documentElement.remove();
document.appendChild(host);
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
is(document.documentElement, host, "Host is the document element");
host.offsetTop;
synthesizeKey("KEY_Tab");
is(shadow.activeElement.id, "shadow-1", "First link in Shadow DOM is focused");
synthesizeKey("KEY_Tab");
is(document.activeElement.id, "slotted", "Slotted link is focused");
synthesizeKey("KEY_Tab");
is(shadow.activeElement.id, "shadow-2", "Second link in Shadow DOM is focused");
// Now backwards.
synthesizeKey("KEY_Tab", {shiftKey: true});
is(document.activeElement.id, "slotted", "Backwards: Slotted link is focused");
synthesizeKey("KEY_Tab", {shiftKey: true});
is(shadow.activeElement.id, "shadow-1", "Backwards: First slotted link is focused");
SimpleTest.finish();
});
</script>

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

@ -7,12 +7,19 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1268556
<title>Test focus behaviour for &lt;input type='number'&gt;</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
#input_test_style_display {
display: none;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268556">Mozilla Bug 1268556</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1057858">Mozilla Bug 1057858</a>
<p id="display"></p>
<div id="content">
<input id="input" type="number">
<input id="input_test_redirect" type="number">
<input id="input_test_style_display" type="number" >
</div>
<pre id="test">
<script type="application/javascript">
@ -22,15 +29,23 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1268556
* This test checks that when focusing on an input type=number, the focus is
* redirected to the anonymous text control, but the document.activeElement
* still returns the <input type=number>.
*
* Tests for bug 1057858.
* Checks that adding an element and immediately focusing it triggers exactly
* one "focus" event and no "blur" events. The same for switching
* `style.display` from `none` to `block`.
**/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() {
test();
test_focus_redirects_to_text_control_but_not_for_activeElement();
test_add_element_and_focus_check_one_focus_event();
test_style_display_none_change_to_block_check_one_focus_event();
SimpleTest.finish();
});
function test() {
var number = document.getElementById("input");
function test_focus_redirects_to_text_control_but_not_for_activeElement() {
document.activeElement.blur();
var number = document.getElementById("input_test_redirect");
number.focus();
// The active element returns the input type=number.
@ -48,6 +63,46 @@ function test() {
is (focusedElement.getAttribute("type"), "text", "focusedElement should of type text");
}
var blurEventCounter = 0;
var focusEventCounter = 0;
function append_input_element_with_event_listeners_to_dom() {
var inputElement = document.createElement("input");
inputElement.type = "number";
inputElement.addEventListener("blur", function() { ++blurEventCounter; });
inputElement.addEventListener("focus", function() { ++focusEventCounter; });
var content = document.getElementById("content");
content.appendChild(inputElement);
return inputElement;
}
function test_add_element_and_focus_check_one_focus_event() {
document.activeElement.blur();
var inputElement = append_input_element_with_event_listeners_to_dom();
blurEventCounter = 0;
focusEventCounter = 0;
inputElement.focus();
is(blurEventCounter, 0, "After focus: no blur events observed.");
is(focusEventCounter, 1, "After focus: exactly one focus event observed.");
}
function test_style_display_none_change_to_block_check_one_focus_event() {
document.activeElement.blur();
var inputElement = document.getElementById("input_test_style_display");
inputElement.addEventListener("blur", function() { ++blurEventCounter; });
inputElement.addEventListener("focus", function() { ++focusEventCounter; });
blurEventCounter = 0;
focusEventCounter = 0;
inputElement.style.display = "block";
inputElement.focus();
is(blurEventCounter, 0, "After focus: no blur events observed.");
is(focusEventCounter, 1, "After focus: exactly one focus event observed.");
}
</script>
</pre>
</body>

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

@ -66,7 +66,9 @@ CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) {
// Format TimeUnit as number of frames at given rate.
CheckedInt64 TimeUnitToFrames(const TimeUnit& aTime, uint32_t aRate) {
return UsecsToFrames(aTime.ToMicroseconds(), aRate);
return aTime.IsValid() ?
UsecsToFrames(aTime.ToMicroseconds(), aRate) :
CheckedInt64(INT64_MAX) + 1;
}
nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs) {

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

@ -456,7 +456,7 @@ static bool ToSessionType(const nsAString& aSessionType,
return false;
}
// 5.2.1 Is persistent session type?
// 5.1.1 Is persistent session type?
static bool IsPersistentSessionType(MediaKeySessionType aSessionType) {
return aSessionType == MediaKeySessionType::Persistent_license;
}
@ -522,7 +522,7 @@ static bool IsParameterUnrecognized(const nsAString& aContentType) {
return false;
}
// 3.1.2.3 Get Supported Capabilities for Audio/Video Type
// 3.1.1.3 Get Supported Capabilities for Audio/Video Type
static Sequence<MediaKeySystemMediaCapability> GetSupportedCapabilities(
const CodecType aCodecType,
const nsTArray<MediaKeySystemMediaCapability>& aRequestedCapabilities,
@ -807,7 +807,7 @@ static bool CheckRequirement(const MediaKeysRequirement aRequirement,
return true;
}
// 3.1.2.2, step 12
// 3.1.1.2, step 12
// Follow the steps for the first matching condition from the following list:
// If the sessionTypes member is present in candidate configuration.
// Let session types be candidate configuration's sessionTypes member.
@ -826,7 +826,7 @@ static Sequence<nsString> UnboxSessionTypes(
return sessionTypes;
}
// 3.1.2.2 Get Supported Configuration and Consent
// 3.1.1.2 Get Supported Configuration and Consent
static bool GetSupportedConfig(
const KeySystemConfig& aKeySystem,
const MediaKeySystemConfiguration& aCandidate,

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

@ -385,7 +385,7 @@ void AudioSink::NotifyAudioNeeded() {
// hardware.
CheckedInt64 missingFrames = sampleTime - mFramesParsed;
if (!missingFrames.isValid()) {
if (!missingFrames.isValid() || !sampleTime.isValid()) {
NS_WARNING("Int overflow in AudioSink");
mErrored = true;
return;

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

@ -151,6 +151,18 @@ function overlayChildNodes(fromFragment, toElement) {
toElement.appendChild(fromFragment);
}
function hasAttribute(attributes, name) {
if (!attributes) {
return false;
}
for (let attr of attributes) {
if (attr.name === name) {
return true;
}
}
return false;
}
/**
* Transplant localizable attributes of an element to another element.
*
@ -167,9 +179,11 @@ function overlayAttributes(fromElement, toElement) {
.split(",").map(i => i.trim())
: null;
// Remove existing localizable attributes.
// Remove existing localizable attributes if they
// will not be used in the new translation.
for (const attr of Array.from(toElement.attributes)) {
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)) {
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)
&& !hasAttribute(fromElement.attributes, attr.name)) {
toElement.removeAttribute(attr.name);
}
}
@ -183,7 +197,8 @@ function overlayAttributes(fromElement, toElement) {
// Set localizable attributes.
for (const attr of Array.from(fromElement.attributes)) {
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)) {
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)
&& toElement.getAttribute(attr.name) !== attr.value) {
toElement.setAttribute(attr.name, attr.value);
}
}
@ -475,10 +490,15 @@ class DOMLocalization extends Localization {
* @param {Object<string, string>} args - KVP list of l10n arguments
* @returns {Element}
*/
setAttributes(element, id, args) {
element.setAttribute(L10NID_ATTR_NAME, id);
setAttributes(element, id, args = null) {
if (element.getAttribute(L10NID_ATTR_NAME) !== id) {
element.setAttribute(L10NID_ATTR_NAME, id);
}
if (args) {
element.setAttribute(L10NARGS_ATTR_NAME, JSON.stringify(args));
let argsString = JSON.stringify(args);
if (argsString !== element.getAttribute(L10NARGS_ATTR_NAME)) {
element.setAttribute(L10NARGS_ATTR_NAME, argsString);
}
} else {
element.removeAttribute(L10NARGS_ATTR_NAME);
}

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

@ -263,10 +263,11 @@ void DocumentL10n::SetAttributes(JSContext* aCx, Element& aElement,
const nsAString& aId,
const Optional<JS::Handle<JSObject*>>& aArgs,
ErrorResult& aRv) {
aElement.SetAttribute(NS_LITERAL_STRING("data-l10n-id"), aId, aRv);
if (aRv.Failed()) {
return;
if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::datal10nid, aId,
eCaseMatters)) {
aElement.SetAttr(kNameSpaceID_None, nsGkAtoms::datal10nid, aId, true);
}
if (aArgs.WasPassed()) {
nsAutoString data;
JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*aArgs.Value()));
@ -274,9 +275,12 @@ void DocumentL10n::SetAttributes(JSContext* aCx, Element& aElement,
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return;
}
aElement.SetAttribute(NS_LITERAL_STRING("data-l10n-args"), data, aRv);
if (!aElement.AttrValueIs(kNameSpaceID_None, nsGkAtoms::datal10nargs, data,
eCaseMatters)) {
aElement.SetAttr(kNameSpaceID_None, nsGkAtoms::datal10nargs, data, true);
}
} else {
aElement.RemoveAttribute(NS_LITERAL_STRING("data-l10n-args"), aRv);
aElement.UnsetAttr(kNameSpaceID_None, nsGkAtoms::datal10nargs, true);
}
}

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

@ -26,3 +26,6 @@
[dom/test_docl10n.html]
[dom/test_docl10n_ready_rejected.html]
[dom/test_docl10n_removeResourceIds.html]
[dom_overlays/test_same_id.html]
[dom_overlays/test_same_id_args.html]

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

@ -0,0 +1,57 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test Amount of mutations generated from DOM Overlays</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<link rel="localization" href="toolkit/about/aboutTelemetry.ftl"/>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
let config = {
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true,
};
let allMutations = [];
document.addEventListener("DOMContentLoaded", async function() {
await document.l10n.ready;
let inputElem = document.getElementById("search-input");
// Test for initial localization applied.
is(inputElem.getAttribute("placeholder").length > 0, true);
let observer = new MutationObserver((mutations) => {
for (let mutation of mutations) {
allMutations.push(mutation);
}
});
observer.observe(inputElem, config);
document.l10n.setAttributes(inputElem, "about-telemetry-filter-all-placeholder");
// Due to the async iteractions between nsINode.localize
// and DOMLocalization.jsm, we'll need to wait two frames
// to verify that no mutations happened.
requestAnimationFrame(() => {
requestAnimationFrame(() => {
// Since the l10n-id is the same as the previous one
// no mutation should happen in result.
is(allMutations.length, 0);
SimpleTest.finish();
});
});
}, { once: true});
</script>
</head>
<body>
<input id="search-input" data-l10n-id="about-telemetry-filter-all-placeholder"></input>
</body>
</html>

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

@ -0,0 +1,57 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test Amount of mutations generated from DOM Overlays</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<link rel="localization" href="toolkit/about/aboutTelemetry.ftl"/>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
let config = {
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true,
};
let allMutations = [];
document.addEventListener("DOMContentLoaded", async function() {
await document.l10n.ready;
let inputElem = document.getElementById("search-input");
// Test for initial localization applied.
is(inputElem.getAttribute("placeholder").length > 0, true);
let observer = new MutationObserver((mutations) => {
for (let mutation of mutations) {
allMutations.push(mutation);
}
});
observer.observe(inputElem, config);
document.l10n.setAttributes(inputElem, "about-telemetry-filter-placeholder", {selectedTitle: "Test"});
// Due to the async iteractions between nsINode.localize
// and DOMLocalization.jsm, we'll need to wait two frames
// to verify that no mutations happened.
requestAnimationFrame(() => {
requestAnimationFrame(() => {
// Since the l10n-id is the same as the previous one
// no mutation should happen in result.
is(allMutations.length, 0);
SimpleTest.finish();
});
});
}, { once: true});
</script>
</head>
<body>
<input id="search-input" data-l10n-id="about-telemetry-filter-placeholder" data-l10n-args='{"selectedTitle":"Test"}'></input>
</body>
</html>

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

@ -47,6 +47,7 @@
#include "mozilla/dom/PointerEventHandler.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "nsAnimationManager.h"
#include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816)
#include "nsFrame.h"
@ -96,6 +97,7 @@
#ifdef MOZ_REFLOW_PERF
# include "nsFontMetrics.h"
#endif
#include "MobileViewportManager.h"
#include "OverflowChangedTracker.h"
#include "PositionedEventTargeting.h"

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

@ -5,7 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ScrollStyles.h"
#include "nsStyleStruct.h" // for nsStyleDisplay and nsStyleBackground::Position
#include "mozilla/WritingModes.h"
#include "nsStyleStruct.h" // for nsStyleDisplay & nsStyleBackground::Position
namespace mozilla {

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

@ -21,6 +21,7 @@
#include "mozilla/dom/BeforeUnloadEvent.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "nsPresContext.h"
#include "nsIFrame.h"
#include "nsIWritablePropertyBag2.h"

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

@ -8,8 +8,11 @@
#define nsLayoutModule_h
#include "nscore.h"
#include "nsID.h"
#include "mozilla/AlreadyAddRefed.h"
class nsIPresentationService;
class nsISupports;
// This function initializes various layout statics, as well as XPConnect.
// It should be called only once, and before the first time any XPCOM module in

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

@ -103,6 +103,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "ThirdPartyUtil.h"
#include "TouchManager.h"
#include "DecoderDoctorLogger.h"
#include "MediaDecoder.h"

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

@ -31,6 +31,7 @@
#include "nsNameSpaceManager.h"
#include "nsCSSAnonBoxes.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/ServoStyleSetInlines.h"
#include "mozilla/dom/Element.h"
#include "nsDisplayList.h"
#include "nsNodeUtils.h"

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

@ -26,7 +26,7 @@ class WebRenderCanvasData;
class nsPresContext;
class nsDisplayItem;
nsIFrame* NS_NewHTMLCanvasFrame(PresShell* aPresShell,
nsIFrame* NS_NewHTMLCanvasFrame(mozilla::PresShell* aPresShell,
mozilla::ComputedStyle* aStyle);
class nsHTMLCanvasFrame final : public nsContainerFrame {

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

@ -95,7 +95,9 @@ public class Tabs implements BundleEventListener {
// Used to indicate a new tab should be appended to the current tabs.
public static final int NEW_LAST_INDEX = -1;
private static final AtomicInteger sTabId = new AtomicInteger(0);
// Bug 1410749: Desktop numbers tabs starting from 1, and various Webextension bits have
// inherited that assumption and treat 0 as an invalid tab.
private static final AtomicInteger sTabId = new AtomicInteger(1);
private volatile boolean mInitialTabsAdded;
private Context mAppContext;

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

@ -49,18 +49,6 @@ add_task(async function test_setTitle_and_getTitle() {
return tab;
}
// Test on tabId 0
// Test that the default title is returned before the title is set for the tab.
let tabTitle = await browser.browserAction.getTitle({tabId: 0});
browser.test.assertEq("Browser Action", tabTitle,
"Expected the default title to be returned for tabId 0");
// Set the title for the new tab and test that getTitle returns the correct title.
await browser.browserAction.setTitle({tabId: 0, title: "tab 0"});
tabTitle = await browser.browserAction.getTitle({tabId: 0});
browser.test.assertEq("tab 0", tabTitle,
"Expected the new tab title to be returned for tabId 0");
// Create and test 3 new tabs.
let tab1 = await createAndTestNewTab("tab 1", "about:blank");
let tab2 = await createAndTestNewTab("tab 2", "about:blank");

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

@ -237,50 +237,6 @@ add_task(async function tabsSendMessageNoExceptionOnNonExistentTab() {
await extension.unload();
});
add_task(async function tabsSendAndReceiveMessageTabId0() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["tabs", "<all_urls>"],
},
async background() {
function contentScriptCode() {
browser.runtime.onMessage.addListener(msg => {
browser.test.assertEq(msg, "message to tabId 0",
"Got the expected message from the background page");
return Promise.resolve("reply to background page");
});
browser.runtime.sendMessage("message from tabId 0");
}
await browser.runtime.onMessage.addListener(async (msg, sender) => {
browser.test.assertEq("message from tabId 0", msg,
"Got the expected message from a content script");
browser.test.assertTrue(sender.tab,
"Got a sender.tab object as expected");
browser.test.assertEq(0, sender.tab.id,
"Got a sender.tab object with tab.id == 0");
const reply = await browser.tabs.sendMessage(0, "message to tabId 0");
browser.test.assertEq("reply to background page", reply);
browser.test.notifyPass("tabs.messaging.tab0");
});
await browser.tabs.executeScript(0, {code: `new ${contentScriptCode}`});
},
});
await extension.startup();
await extension.awaitFinish("tabs.messaging.tab0");
await extension.unload();
});
</script>
</body>

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

@ -0,0 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.geckoview;
import org.mozilla.gecko.util.EventCallback;
/* package */ abstract class CallbackResult<T> extends GeckoResult<T>
implements EventCallback {
@Override
public void sendError(final Object response) {
completeExceptionally(response != null ?
new Exception(response.toString()) :
new UnknownError());
}
}

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

@ -289,7 +289,7 @@ public final class GeckoRuntime implements Parcelable {
@UiThread
public @NonNull GeckoResult<Void> registerWebExtension(
final @NonNull WebExtension webExtension) {
final GeckoSession.CallbackResult<Void> result = new GeckoSession.CallbackResult<Void>() {
final CallbackResult<Void> result = new CallbackResult<Void>() {
@Override
public void sendSuccess(final Object response) {
complete(null);

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

@ -266,16 +266,6 @@ public class GeckoSession implements Parcelable {
return mCompositorReady ? mCompositor : null;
}
/* package */ static abstract class CallbackResult<T> extends GeckoResult<T>
implements EventCallback {
@Override
public void sendError(final Object response) {
completeExceptionally(response != null ?
new Exception(response.toString()) :
new UnknownError());
}
}
private final GeckoSessionHandler<HistoryDelegate> mHistoryHandler =
new GeckoSessionHandler<HistoryDelegate>(
"GeckoViewHistory", this,

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

@ -42,17 +42,16 @@ public final class RuntimeTelemetry {
final GeckoBundle msg = new GeckoBundle(1);
msg.putBoolean("clear", clear);
final GeckoSession.CallbackResult<JSONObject> result =
new GeckoSession.CallbackResult<JSONObject>() {
@Override
public void sendSuccess(final Object value) {
try {
complete(((GeckoBundle) value).toJSONObject());
} catch (JSONException ex) {
completeExceptionally(ex);
}
final CallbackResult<JSONObject> result = new CallbackResult<JSONObject>() {
@Override
public void sendSuccess(final Object value) {
try {
complete(((GeckoBundle) value).toJSONObject());
} catch (JSONException ex) {
completeExceptionally(ex);
}
};
}
};
mEventDispatcher.dispatch("GeckoView:TelemetrySnapshots", msg, result);

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

@ -85,8 +85,7 @@ public final class SessionFinder {
bundle.putString("searchString", searchString);
addFlagsToBundle(flags, bundle);
final GeckoSession.CallbackResult<FinderResult> result =
new GeckoSession.CallbackResult<FinderResult>() {
final CallbackResult<FinderResult> result = new CallbackResult<FinderResult>() {
@Override
public void sendSuccess(final Object response) {
complete(new FinderResult((GeckoBundle) response));

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

@ -23,7 +23,10 @@ class Tab {
// Stub BrowserApp implementation for WebExtensions support.
class GeckoViewTab extends GeckoViewModule {
onInit() {
const tab = new Tab(0, this.browser);
// As this is only a stub implementation, we hardcode a single tab ID.
// Because of bug 1410749, we can't use 0, though, and just to be safe
// we choose a value that is unlikely to overlap with Fennec's tab IDs.
const tab = new Tab(10001, this.browser);
this.window.gBrowser = this.window.BrowserApp = {
selectedBrowser: this.browser,

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

@ -2764,7 +2764,9 @@ class StaticAnalysis(MachCommandBase):
path = repo.get_outgoing_files()
if path:
path = map(os.path.abspath, path)
# Create the full path list
path_maker = lambda f_name: os.path.join(self.topsrcdir, f_name)
path = map(path_maker, path)
os.chdir(self.topsrcdir)

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

@ -652,7 +652,8 @@ void SetMediaPluginSandbox(const char* aFilePath) {
}
void SetRemoteDataDecoderSandbox(int aBroker) {
if (PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX") != nullptr) {
if (!SandboxInfo::Get().Test(SandboxInfo::kHasSeccompBPF) ||
PR_GetEnv("MOZ_DISABLE_RDD_SANDBOX")) {
if (aBroker >= 0) {
close(aBroker);
}

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

@ -629,6 +629,13 @@ class SandboxPolicyCommon : public SandboxPolicyBase {
case __NR_getrandom:
return Allow();
#ifdef DESKTOP
// Bug 1543858: glibc's qsort calls sysinfo to check the
// memory size; it falls back to assuming there's enough RAM.
case __NR_sysinfo:
return Error(EPERM);
#endif
#ifdef MOZ_ASAN
// ASAN's error reporter wants to know if stderr is a tty.
case __NR_ioctl: {

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

@ -262,12 +262,15 @@ win32-shippable/opt:
shippable: true
enable-full-crashsymbols: true
stub-installer:
by-project:
default: false
mozilla-central: true
try: true
mozilla-beta: true
mozilla-release: true
by-release-type:
nightly: true
beta: true
release: true
default:
by-project:
# browser/confvars.sh looks for nightly-try
try: true
default: false
shipping-phase: build
shipping-product: firefox
treeherder:
@ -821,12 +824,15 @@ win32-devedition-nightly/opt:
nightly: true
enable-full-crashsymbols: true
stub-installer:
by-project:
default: false
mozilla-central: true
try: true
mozilla-beta: true
mozilla-release: true
by-release-type:
nightly: true
beta: true
release: true
default:
by-project:
# browser/confvars.sh looks for nightly-try
try: true
default: false
shipping-phase: build
shipping-product: devedition
treeherder:

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

@ -49,12 +49,16 @@ devtools-tests:
yarn test &&
cd /builds/worker/checkouts/gecko/devtools/client/webconsole/test &&
yarn &&
yarn test &&
cd /builds/worker/checkouts/gecko/devtools/client/netmonitor/test &&
yarn &&
yarn test
when:
files-changed:
- 'devtools/client/aboutdebugging-new/src/components/**'
- 'devtools/client/framework/components/**'
- 'devtools/client/webconsole/**'
- 'devtools/client/netmonitor/**'
eslint-plugin-mozilla:
description: eslint-plugin-mozilla integration tests

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

@ -43,7 +43,10 @@ def set_defaults(config, jobs):
def stub_installer(config, jobs):
for job in jobs:
resolve_keyed_by(
job, 'stub-installer', item_name=job['name'], project=config.params['project']
job, 'stub-installer', item_name=job['name'], project=config.params['project'],
**{
'release-type': config.params['release_type'],
}
)
job.setdefault('attributes', {})
if job.get('stub-installer'):

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

@ -140,10 +140,18 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
}],
[["--power-test"], {
"dest": "power_test",
"action": "store_true",
"default": False,
"help": "Use Raptor to measure power usage. Currently only supported for Geckoview. "
"The host ip address must be specified either via the --host command line "
"argument.",
}],
[["--memory-test"], {
"dest": "memory_test",
"action": "store_true",
"default": False,
"help": "Use Raptor to measure memory usage.",
}],
[["--debug-mode"], {
"dest": "debug_mode",
"action": "store_true",
@ -225,6 +233,7 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
if self.host == 'HOST_IP':
self.host = os.environ['HOST_IP']
self.power_test = self.config.get('power_test')
self.memory_test = self.config.get('memory_test')
self.is_release_build = self.config.get('is_release_build')
self.debug_mode = self.config.get('debug_mode', False)
self.firefox_android_browsers = ["fennec", "geckoview", "refbrow", "fenix"]
@ -362,6 +371,8 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
options.extend(['--is-release-build'])
if self.config.get('power_test', False):
options.extend(['--power-test'])
if self.config.get('memory_test', False):
options.extend(['--memory-test'])
for key, value in kw_options.items():
options.extend(['--%s' % key, value])
@ -473,6 +484,8 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
expected_perfherder = 1
if self.config.get('power_test', None):
expected_perfherder += 1
if self.config.get('memory_test', None):
expected_perfherder += 1
if len(parser.found_perf_data) != expected_perfherder:
self.critical("PERFHERDER_DATA was seen %d times, expected %d."
% (len(parser.found_perf_data), expected_perfherder))
@ -608,6 +621,10 @@ class Raptor(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidMixin):
src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'raptor-power.json')
self._artifact_perf_data(src, dest)
if self.memory_test:
src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'raptor-memory.json')
self._artifact_perf_data(src, dest)
src = os.path.join(self.query_abs_dirs()['abs_work_dir'], 'screenshots.html')
if os.path.exists(src):
dest = os.path.join(env['MOZ_UPLOAD_DIR'], 'screenshots.html')

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

@ -60,6 +60,7 @@ class RaptorRunner(MozbuildObject):
kwargs['host'] = os.environ['HOST_IP']
self.host = kwargs['host']
self.power_test = kwargs['power_test']
self.memory_test = kwargs['memory_test']
self.is_release_build = kwargs['is_release_build']
def setup_benchmarks(self):
@ -139,6 +140,7 @@ class RaptorRunner(MozbuildObject):
'raptor_cmd_line_args': self.raptor_args,
'host': self.host,
'power_test': self.power_test,
'memory_test': self.memory_test,
'is_release_build': self.is_release_build,
}

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

@ -69,6 +69,8 @@ def create_parser(mach_interface=False):
add_arg('--power-test', dest="power_test", action="store_true",
help="Use Raptor to measure power usage. Currently supported for Geckoview. "
"The host ip address must be specified via the --host command line argument.")
add_arg('--memory-test', dest="memory_test", action="store_true",
help="Use Raptor to measure memory usage.")
add_arg('--is-release-build', dest="is_release_build", default=False,
action='store_true',
help="Whether the build is a release build which requires work arounds "

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

@ -7,10 +7,12 @@
from __future__ import absolute_import
import BaseHTTPServer
import datetime
import json
import os
import socket
import threading
import time
from mozlog import get_proxy_logger
@ -22,6 +24,81 @@ here = os.path.abspath(os.path.dirname(__file__))
def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_profile):
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler, object):
"""
Control server expects messages of the form
{'type': 'messagetype', 'data':...}
Each message is given a key which is calculated as
If type is 'webext_status', then
the key is data['type']/data['data']
otherwise
the key is data['type'].
The contol server can be forced to wait before performing an
action requested via POST by sending a special message
{'type': 'wait-set', 'data': key}
where key is the key of the message control server should
perform a wait before processing. The handler will store
this key in the wait_after_messages dict as a True value.
wait_after_messages[key] = True
For subsequent requests the handler will check the key of
the incoming message against wait_for_messages and if it is
found and its value is True, the handler will assign the key
to waiting_in_state and will loop until the key is removed
or until its value is changed to False.
Control server will stop waiting for a state to be continued
or cleared after wait_timeout seconds after which the wait
will be removed and the control server will finish processing
the current POST request. wait_timeout defaults to 60 seconds
but can be set globally for all wait states by sending the
message
{'type': 'wait-timeout', 'data': timeout}
The value of waiting_in_state can be retrieved by sending the
message
{'type': 'wait-get', 'data': ''}
which will return the value of waiting_in_state in the
content of the response. If the value returned is not
'None', then the control server has received a message whose
key is recorded in wait_after_messages and is waiting before
completing the request.
The control server can be told to stop waiting and to finish
processing the current request while keeping the wait for
subsequent requests by sending
{'type': 'wait-continue', 'data': ''}
The control server can be told to stop waiting and to finish
processing the current request while removing the wait for
subsequent requests by sending
{'type': 'wait-clear', 'data': key}
if key is the empty string ''
the key in waiting_in_state is removed from wait_after_messages
waiting_in_state is set to None
else if key is 'all'
all keys in wait_after_messages are removed
else key is not in wait_after_messages
the message is ignored
else
the key is removed from wait_after messages
if the key matches the value in waiting_in_state,
then waiting_in_state is set to None
"""
wait_after_messages = {}
waiting_in_state = None
wait_timeout = 60
def __init__(self, *args, **kwargs):
self.results_handler = results_handler
@ -29,6 +106,10 @@ def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_pr
self.write_raw_gecko_profile = write_raw_gecko_profile
super(MyHandler, self).__init__(*args, **kwargs)
def log_request(self, code='-', size='-'):
if code != 200:
super(MyHandler, self).log_request(code, size)
def do_GET(self):
# get handler, received request for test settings from web ext runner
self.send_response(200)
@ -61,6 +142,32 @@ def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_pr
# could have received a status update or test results
data = json.loads(post_body)
if data['type'] == 'webext_status':
wait_key = "%s/%s" % (data['type'], data['data'])
else:
wait_key = data['type']
if MyHandler.wait_after_messages.get(wait_key, None):
LOG.info("Waiting in %s" % wait_key)
MyHandler.waiting_in_state = wait_key
start_time = datetime.datetime.now()
while MyHandler.wait_after_messages.get(wait_key, None):
time.sleep(1)
elapsed_time = datetime.datetime.now() - start_time
if elapsed_time > datetime.timedelta(seconds=MyHandler.wait_timeout):
del MyHandler.wait_after_messages[wait_key]
MyHandler.waiting_in_state = None
LOG.error("TEST-UNEXPECTED-ERROR | "
"ControlServer wait %s exceeded %s seconds" %
(wait_key, MyHandler.wait_timeout))
if MyHandler.wait_after_messages.get(wait_key, None) is not None:
# If the wait is False, it was continued and we just set it back
# to True for the next time. If it was removed by clear, we
# leave it alone so it will not cause a wait any more.
MyHandler.wait_after_messages[wait_key] = True
if data['type'] == "webext_gecko_profile":
# received gecko profiling results
_test = str(data['data'][0])
@ -80,7 +187,7 @@ def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_pr
self.results_handler.add_page_timeout(str(data['data'][0]),
str(data['data'][1]),
dict(data['data'][2]))
elif data['data'] == "__raptor_shutdownBrowser":
elif data['type'] == 'webext_status' and data['data'] == "__raptor_shutdownBrowser":
LOG.info("received " + data['type'] + ": " + str(data['data']))
# webext is telling us it's done, and time to shutdown the browser
self.shutdown_browser()
@ -89,6 +196,39 @@ def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_pr
self.results_handler.add_image(str(data['data'][0]),
str(data['data'][1]),
str(data['data'][2]))
elif data['type'] == 'webext_status':
LOG.info("received " + data['type'] + ": " + str(data['data']))
elif data['type'] == 'wait-set':
LOG.info("received " + data['type'] + ": " + str(data['data']))
MyHandler.wait_after_messages[str(data['data'])] = True
elif data['type'] == 'wait-timeout':
LOG.info("received " + data['type'] + ": " + str(data['data']))
MyHandler.wait_timeout = data['data']
elif data['type'] == 'wait-get':
self.wfile.write(MyHandler.waiting_in_state)
elif data['type'] == 'wait-continue':
LOG.info("received " + data['type'] + ": " + str(data['data']))
if MyHandler.waiting_in_state:
MyHandler.wait_after_messages[MyHandler.waiting_in_state] = False
MyHandler.waiting_in_state = None
elif data['type'] == 'wait-clear':
LOG.info("received " + data['type'] + ": " + str(data['data']))
clear_key = str(data['data'])
if clear_key == '':
if MyHandler.waiting_in_state:
del MyHandler.wait_after_messages[MyHandler.waiting_in_state]
MyHandler.waiting_in_state = None
else:
pass
elif clear_key == 'all':
MyHandler.wait_after_messages = {}
MyHandler.waiting_in_state = None
elif clear_key not in MyHandler.wait_after_messages:
pass
else:
del MyHandler.wait_after_messages[clear_key]
if MyHandler.waiting_in_state == clear_key:
MyHandler.waiting_in_state = None
else:
LOG.info("received " + data['type'] + ": " + str(data['data']))
@ -103,6 +243,19 @@ def MakeCustomHandlerClass(results_handler, shutdown_browser, write_raw_gecko_pr
return MyHandler
class ThreadedHTTPServer(BaseHTTPServer.HTTPServer):
# See
# https://stackoverflow.com/questions/19537132/threaded-basehttpserver-one-thread-per-request#30312766
def process_request(self, request, client_address):
thread = threading.Thread(target=self.__new_request,
args=(self.RequestHandlerClass, request, client_address, self))
thread.start()
def __new_request(self, handlerClass, request, address, server):
handlerClass(request, address, server)
self.shutdown_request(request)
class RaptorControlServer():
"""Container class for Raptor Control Server"""
@ -130,7 +283,7 @@ class RaptorControlServer():
sock.close()
server_address = ('', self.port)
server_class = BaseHTTPServer.HTTPServer
server_class = ThreadedHTTPServer
handler_class = MakeCustomHandlerClass(self.results_handler,
self.shutdown_browser,
self.write_raw_gecko_profile)

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

@ -0,0 +1,43 @@
# 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/.
from __future__ import absolute_import
import re
def get_app_memory_usage(raptor):
app_name = raptor.config['binary']
total = 0
re_total_memory = re.compile(r'TOTAL:\s+(\d+)')
verbose = raptor.device._verbose
raptor.device._verbose = False
meminfo = raptor.device.shell_output("dumpsys meminfo %s" % app_name).split('\n')
raptor.device._verbose = verbose
for line in meminfo:
match = re_total_memory.search(line)
if match:
total = int(match.group(1))
break
return total
def generate_android_memory_profile(raptor, test_name):
if not raptor.device or not raptor.config['memory_test']:
return
foreground = get_app_memory_usage(raptor)
# put app into background
verbose = raptor.device._verbose
raptor.device._verbose = False
raptor.device.shell_output("am start -a android.intent.action.MAIN "
"-c android.intent.category.HOME")
raptor.device._verbose = verbose
background = get_app_memory_usage(raptor)
meminfo_data = {'type': 'memory',
'test': test_name,
'unit': 'KB',
'values': {
'foreground': foreground,
'background': background
}}
raptor.control_server.submit_supporting_data(meminfo_data)

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

@ -13,6 +13,8 @@ import sys
import tempfile
import time
import requests
import mozcrash
import mozinfo
from mozdevice import ADBDevice
@ -57,6 +59,7 @@ from mozproxy import get_playback
from results import RaptorResultsHandler
from gecko_profile import GeckoProfile
from power import init_android_power_test, finish_android_power_test
from memory import generate_android_memory_profile
from utils import view_gecko_profile
@ -65,8 +68,8 @@ class Raptor(object):
def __init__(self, app, binary, run_local=False, obj_path=None,
gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
symbols_path=None, host=None, power_test=False, is_release_build=False,
debug_mode=False, post_startup_delay=None, activity=None):
symbols_path=None, host=None, power_test=False, memory_test=False,
is_release_build=False, debug_mode=False, post_startup_delay=None, activity=None):
# Override the magic --host HOST_IP with the value of the environment variable.
if host == 'HOST_IP':
@ -84,7 +87,9 @@ class Raptor(object):
self.config['symbols_path'] = symbols_path
self.config['host'] = host
self.config['power_test'] = power_test
self.config['memory_test'] = memory_test
self.config['is_release_build'] = is_release_build
self.config['enable_control_server_wait'] = memory_test
self.raptor_venv = os.path.join(os.getcwd(), 'raptor-venv')
self.log = get_default_logger(component='raptor-main')
self.control_server = None
@ -187,6 +192,9 @@ class Raptor(object):
self.control_server = RaptorControlServer(self.results_handler, self.debug_mode)
self.control_server.start()
if self.config['enable_control_server_wait']:
self.control_server_wait_set('webext_status/__raptor_shutdownBrowser')
# for android we must make the control server available to the device
if self.config['app'] in self.firefox_android_apps and \
self.config['host'] in ('localhost', '127.0.0.1'):
@ -336,6 +344,12 @@ class Raptor(object):
elapsed_time = 0
while not self.control_server._finished:
if self.config['enable_control_server_wait']:
response = self.control_server_wait_get()
if response == 'webext_status/__raptor_shutdownBrowser':
if self.config['memory_test']:
generate_android_memory_profile(self, test['name'])
self.control_server_wait_continue()
time.sleep(1)
# we only want to force browser-shutdown on timeout if not in debug mode;
# in debug-mode we leave the browser running (require manual shutdown)
@ -365,6 +379,9 @@ class Raptor(object):
return self.results_handler.page_timeout_list
def clean_up(self):
if self.config['enable_control_server_wait']:
self.control_server_wait_clear('all')
self.control_server.stop()
if self.config['app'] not in self.firefox_android_apps:
self.runner.stop()
@ -375,15 +392,40 @@ class Raptor(object):
pass
self.log.info("finished")
def control_server_wait_set(self, state):
response = requests.post("http://127.0.0.1:%s/" % self.control_server.port,
json={"type": "wait-set", "data": state})
return response.content
def control_server_wait_timeout(self, timeout):
response = requests.post("http://127.0.0.1:%s/" % self.control_server.port,
json={"type": "wait-timeout", "data": timeout})
return response.content
def control_server_wait_get(self):
response = requests.post("http://127.0.0.1:%s/" % self.control_server.port,
json={"type": "wait-get", "data": ""})
return response.content
def control_server_wait_continue(self):
response = requests.post("http://127.0.0.1:%s/" % self.control_server.port,
json={"type": "wait-continue", "data": ""})
return response.content
def control_server_wait_clear(self, state):
response = requests.post("http://127.0.0.1:%s/" % self.control_server.port,
json={"type": "wait-clear", "data": state})
return response.content
class RaptorDesktop(Raptor):
def __init__(self, app, binary, run_local=False, obj_path=None,
gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
symbols_path=None, host=None, power_test=False, is_release_build=False,
debug_mode=False, post_startup_delay=None, activity=None):
symbols_path=None, host=None, power_test=False, memory_test=False,
is_release_build=False, debug_mode=False, post_startup_delay=None, activity=None):
Raptor.__init__(self, app, binary, run_local, obj_path, gecko_profile,
gecko_profile_interval, gecko_profile_entries, symbols_path,
host, power_test, is_release_build, debug_mode,
host, power_test, memory_test, is_release_build, debug_mode,
post_startup_delay)
def create_browser_handler(self):
@ -446,11 +488,11 @@ class RaptorDesktop(Raptor):
class RaptorDesktopFirefox(RaptorDesktop):
def __init__(self, app, binary, run_local=False, obj_path=None,
gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
symbols_path=None, host=None, power_test=False, is_release_build=False,
debug_mode=False, post_startup_delay=None, activity=None):
symbols_path=None, host=None, power_test=False, memory_test=False,
is_release_build=False, debug_mode=False, post_startup_delay=None, activity=None):
RaptorDesktop.__init__(self, app, binary, run_local, obj_path, gecko_profile,
gecko_profile_interval, gecko_profile_entries, symbols_path,
host, power_test, is_release_build, debug_mode,
host, power_test, memory_test, is_release_build, debug_mode,
post_startup_delay)
def disable_non_local_connections(self):
@ -491,11 +533,11 @@ class RaptorDesktopFirefox(RaptorDesktop):
class RaptorDesktopChrome(RaptorDesktop):
def __init__(self, app, binary, run_local=False, obj_path=None,
gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
symbols_path=None, host=None, power_test=False, is_release_build=False,
debug_mode=False, post_startup_delay=None, activity=None):
symbols_path=None, host=None, power_test=False, memory_test=False,
is_release_build=False, debug_mode=False, post_startup_delay=None, activity=None):
RaptorDesktop.__init__(self, app, binary, run_local, obj_path, gecko_profile,
gecko_profile_interval, gecko_profile_entries, symbols_path,
host, power_test, is_release_build, debug_mode,
host, power_test, memory_test, is_release_build, debug_mode,
post_startup_delay)
def setup_chrome_desktop_for_playback(self):
@ -530,11 +572,11 @@ class RaptorDesktopChrome(RaptorDesktop):
class RaptorAndroid(Raptor):
def __init__(self, app, binary, run_local=False, obj_path=None,
gecko_profile=False, gecko_profile_interval=None, gecko_profile_entries=None,
symbols_path=None, host=None, power_test=False, is_release_build=False,
debug_mode=False, post_startup_delay=None, activity=None):
symbols_path=None, host=None, power_test=False, memory_test=False,
is_release_build=False, debug_mode=False, post_startup_delay=None, activity=None):
Raptor.__init__(self, app, binary, run_local, obj_path, gecko_profile,
gecko_profile_interval, gecko_profile_entries, symbols_path, host,
power_test, is_release_build, debug_mode, post_startup_delay)
power_test, memory_test, is_release_build, debug_mode, post_startup_delay)
# on android, when creating the browser profile, we want to use a 'firefox' type profile
self.profile_class = "firefox"
@ -847,6 +889,7 @@ def main(args=sys.argv[1:]):
symbols_path=args.symbols_path,
host=args.host,
power_test=args.power_test,
memory_test=args.memory_test,
is_release_build=args.is_release_build,
debug_mode=args.debug_mode,
post_startup_delay=args.post_startup_delay,

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

@ -16,7 +16,8 @@ def test_verify_options(filedir):
page_cycles=1,
page_timeout=60000,
debug='True',
power_test=False)
power_test=False,
memory_test=False)
parser = ArgumentParser()
with pytest.raises(SystemExit):
@ -31,7 +32,8 @@ def test_verify_options(filedir):
gecko_profile='False',
is_release_build=False,
host='sophie',
power_test=False)
power_test=False,
memory_test=False)
verify_options(parser, args) # assert no exception
args = Namespace(app='refbrow',
@ -40,7 +42,8 @@ def test_verify_options(filedir):
gecko_profile='False',
is_release_build=False,
host='sophie',
power_test=False)
power_test=False,
memory_test=False)
verify_options(parser, args) # assert no exception
args = Namespace(app='fenix',
@ -49,7 +52,8 @@ def test_verify_options(filedir):
gecko_profile='False',
is_release_build=False,
host='sophie',
power_test=False)
power_test=False,
memory_test=False)
verify_options(parser, args) # assert no exception
args = Namespace(app='refbrow',
@ -58,7 +62,8 @@ def test_verify_options(filedir):
gecko_profile='False',
is_release_build=False,
host='sophie',
power_test=False)
power_test=False,
memory_test=False)
parser = ArgumentParser()
verify_options(parser, args) # also will work as uses default activity

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

@ -91,6 +91,67 @@ def test_start_and_stop_server(raptor):
assert not raptor.control_server._server_thread.is_alive()
def test_server_wait_states(raptor):
import datetime
import requests
def post_state():
requests.post("http://127.0.0.1:%s/" % raptor.control_server.port,
json={"type": "webext_status",
"data": "test status"})
assert raptor.control_server is None
raptor.create_browser_profile()
raptor.create_browser_handler()
raptor.start_control_server()
wait_time = 5
message_state = 'webext_status/test status'
rhc = raptor.control_server.server.RequestHandlerClass
# Test initial state
assert rhc.wait_after_messages == {}
assert rhc.waiting_in_state is None
assert rhc.wait_timeout == 60
assert raptor.control_server_wait_get() == 'None'
# Test setting a state
assert raptor.control_server_wait_set(message_state) == ''
assert message_state in rhc.wait_after_messages
assert rhc.wait_after_messages[message_state]
# Test clearing a non-existent state
assert raptor.control_server_wait_clear('nothing') == ''
assert message_state in rhc.wait_after_messages
# Test clearing a state
assert raptor.control_server_wait_clear(message_state) == ''
assert message_state not in rhc.wait_after_messages
# Test clearing all states
assert raptor.control_server_wait_set(message_state) == ''
assert message_state in rhc.wait_after_messages
assert raptor.control_server_wait_clear('all') == ''
assert rhc.wait_after_messages == {}
# Test wait timeout
# Block on post request
assert raptor.control_server_wait_set(message_state) == ''
assert rhc.wait_after_messages[message_state]
assert raptor.control_server_wait_timeout(wait_time) == ''
assert rhc.wait_timeout == wait_time
start = datetime.datetime.now()
post_state()
assert datetime.datetime.now() - start < datetime.timedelta(seconds=wait_time+2)
assert raptor.control_server_wait_get() == 'None'
assert message_state not in rhc.wait_after_messages
raptor.clean_up()
assert not raptor.control_server._server_thread.is_alive()
@pytest.mark.parametrize('app', [
'firefox',
pytest.mark.xfail('chrome'),

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

@ -13,7 +13,7 @@
"tests": ["tart_flex", "ts_paint_flex"]
},
"other": {
"tests": ["a11yr", "ts_paint", "tpaint", "twinopen", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint", "cpstartup", "startup_about_home_paint"]
"tests": ["a11yr", "ts_paint", "twinopen", "sessionrestore", "sessionrestore_no_auto_restore", "tabpaint", "cpstartup", "startup_about_home_paint"]
},
"sessionrestore-many-windows": {
"tests": ["sessionrestore_many_windows"]

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

@ -270,26 +270,6 @@ class QuantumPageloadTest(PageloaderTest):
fnbpaint = True
@register_test()
class tpaint(PageloaderTest):
"""
Tests the amount of time it takes the open a new window. This test does
not include startup time. Multiple test windows are opened in succession,
results reported are the average amount of time required to create and
display a window in the running instance of the browser.
(Measures ctrl-n performance.)
"""
tpmanifest = '${talos}/tests/tpaint/tpaint.manifest'
tppagecycles = 20
timeout = 300
gecko_profile_interval = 1
gecko_profile_entries = 2000000
tpmozafterpaint = True
filters = filter.ignore_first.prepare(5) + filter.median.prepare()
unit = 'ms'
preferences = {'security.data_uri.block_toplevel_data_uri_navigations': False}
@register_test()
class twinopen(PageloaderTest):
"""

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