Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2016-07-26 11:57:38 +02:00
Родитель d3cb1d23af 574d0d452b
Коммит aa2bc77d7f
131 изменённых файлов: 2711 добавлений и 1385 удалений

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

@ -66,33 +66,14 @@ tasks:
env: env:
# checkout-gecko uses these to check out the source; the inputs # checkout-gecko uses these to check out the source; the inputs
# to `mach taskgraph decision` are all on the command line. # to `mach taskgraph decision` are all on the command line.
GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-central' GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
GECKO_HEAD_REPOSITORY: '{{{url}}}' GECKO_HEAD_REPOSITORY: '{{{url}}}'
GECKO_HEAD_REF: '{{revision}}' GECKO_HEAD_REF: '{{revision}}'
GECKO_HEAD_REV: '{{revision}}' GECKO_HEAD_REV: '{{revision}}'
# Arguments passed into `mach taskgraph decision`
cache: # TODO use mozilla-unified for the base repository once the tc-vcs
level-{{level}}-{{project}}-tc-vcs-public-sources: /home/worker/.tc-vcs/ # tar.gz archives are created or tc-vcs isn't being used.
level-{{level}}-{{project}}-gecko-decision: /home/worker/workspace DECISION_ARGS: >
features:
taskclusterProxy: true
# Note: This task is built server side without the context or tooling that
# exist in tree so we must hard code the version
image: 'taskcluster/decision:0.1.0'
maxRunTime: 1800
command:
- /bin/bash
- -cx
- >
mkdir -p /home/worker/artifacts &&
checkout-gecko workspace &&
cd workspace/gecko &&
ln -s /home/worker/artifacts artifacts &&
./mach taskgraph decision
--pushlog-id='{{pushlog_id}}' --pushlog-id='{{pushlog_id}}'
--project='{{project}}' --project='{{project}}'
--message='{{comment}}' --message='{{comment}}'
@ -104,6 +85,22 @@ tasks:
--head-rev='{{revision}}' --head-rev='{{revision}}'
--revision-hash='{{revision_hash}}' --revision-hash='{{revision_hash}}'
cache:
level-{{level}}-hg-shared: /home/worker/hg-shared
level-{{level}}-{{project}}-gecko-decision: /home/worker/workspace
features:
taskclusterProxy: true
# Note: This task is built server side without the context or tooling that
# exist in tree so we must hard code the version
image: 'taskcluster/decision:0.1.2'
maxRunTime: 1800
command:
- /home/worker/bin/run-decision
artifacts: artifacts:
'public': 'public':
type: 'directory' type: 'directory'

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

@ -7452,7 +7452,7 @@ var gRemoteTabsUI = {
* passed via this object. * passed via this object.
* This object also allows: * This object also allows:
* - 'ignoreFragment' property to be set to true to exclude fragment-portion * - 'ignoreFragment' property to be set to true to exclude fragment-portion
* matching when comparing URIs. * matching when comparing URIs. Fragment will be replaced.
* - 'ignoreQueryString' property to be set to true to exclude query string * - 'ignoreQueryString' property to be set to true to exclude query string
* matching when comparing URIs. * matching when comparing URIs.
* - 'replaceQueryString' property to be set to true to exclude query string * - 'replaceQueryString' property to be set to true to exclude query string
@ -7488,32 +7488,42 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
return false; return false;
} }
//Remove the query string, fragment, both, or neither from a given url.
function cleanURL(url, removeQuery, removeFragment) {
let ret = url;
if (removeFragment) {
ret = ret.split("#")[0];
if (removeQuery) {
// This removes a query, if present before the fragment.
ret = ret.split("?")[0];
}
} else if (removeQuery) {
// This is needed in case there is a fragment after the query.
let fragment = ret.split("#")[1];
ret = ret.split("?")[0].concat(
(fragment != undefined) ? "#".concat(fragment) : "");
}
return ret;
}
// Need to handle nsSimpleURIs here too (e.g. about:...), which don't
// work correctly with URL objects - so treat them as strings
let requestedCompare = cleanURL(
aURI.spec, ignoreQueryString || replaceQueryString, ignoreFragment);
let browsers = aWindow.gBrowser.browsers; let browsers = aWindow.gBrowser.browsers;
for (let i = 0; i < browsers.length; i++) { for (let i = 0; i < browsers.length; i++) {
let browser = browsers[i]; let browser = browsers[i];
if (ignoreFragment ? browser.currentURI.equalsExceptRef(aURI) : let browserCompare = cleanURL(
browser.currentURI.equals(aURI)) { browser.currentURI.spec, ignoreQueryString || replaceQueryString, ignoreFragment);
// Focus the matching window & tab if (requestedCompare == browserCompare) {
aWindow.focus(); aWindow.focus();
if (ignoreFragment) { if (ignoreFragment || replaceQueryString) {
let spec = aURI.spec;
browser.loadURI(spec);
}
aWindow.gBrowser.tabContainer.selectedIndex = i;
return true;
}
if (ignoreQueryString || replaceQueryString) {
if (browser.currentURI.spec.split("?")[0] == aURI.spec.split("?")[0]) {
// Focus the matching window & tab
aWindow.focus();
if (replaceQueryString) {
browser.loadURI(aURI.spec); browser.loadURI(aURI.spec);
} }
aWindow.gBrowser.tabContainer.selectedIndex = i; aWindow.gBrowser.tabContainer.selectedIndex = i;
return true; return true;
} }
} }
}
return false; return false;
} }

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

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
add_task(function test_ignoreFragment() { add_task(function *test_ignoreFragment() {
let tabRefAboutHome = gBrowser.addTab("about:home#1"); let tabRefAboutHome = gBrowser.addTab("about:home#1");
yield promiseTabLoaded(tabRefAboutHome); yield promiseTabLoaded(tabRefAboutHome);
let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); let tabRefAboutMozilla = gBrowser.addTab("about:mozilla");
@ -35,7 +35,7 @@ add_task(function test_ignoreFragment() {
cleanupTestTabs(); cleanupTestTabs();
}); });
add_task(function test_ignoreQueryString() { add_task(function* test_ignoreQueryString() {
let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox"); let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox");
yield promiseTabLoaded(tabRefAboutHome); yield promiseTabLoaded(tabRefAboutHome);
let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); let tabRefAboutMozilla = gBrowser.addTab("about:mozilla");
@ -52,7 +52,7 @@ add_task(function test_ignoreQueryString() {
cleanupTestTabs(); cleanupTestTabs();
}); });
add_task(function test_replaceQueryString() { add_task(function* test_replaceQueryString() {
let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox"); let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox");
yield promiseTabLoaded(tabRefAboutHome); yield promiseTabLoaded(tabRefAboutHome);
let tabRefAboutMozilla = gBrowser.addTab("about:mozilla"); let tabRefAboutMozilla = gBrowser.addTab("about:mozilla");
@ -72,6 +72,38 @@ add_task(function test_replaceQueryString() {
cleanupTestTabs(); cleanupTestTabs();
}); });
add_task(function* test_replaceQueryStringAndFragment() {
let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox#aaa");
yield promiseTabLoaded(tabRefAboutHome);
let tabRefAboutMozilla = gBrowser.addTab("about:mozilla?hello=firefoxos#aaa");
yield promiseTabLoaded(tabRefAboutMozilla);
gBrowser.selectedTab = tabRefAboutMozilla;
switchTab("about:home", false);
gBrowser.removeCurrentTab();
switchTab("about:home?hello=firefox#aaa", true);
is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
switchTab("about:mozilla?hello=firefox#bbb", true, { replaceQueryString: true, ignoreFragment: true });
is(tabRefAboutMozilla, gBrowser.selectedTab, "Selected tab should be the initial about:mozilla tab");
switchTab("about:home?hello=firefoxos#bbb", true, { ignoreQueryString: true, ignoreFragment: true });
is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
cleanupTestTabs();
});
add_task(function* test_ignoreQueryStringIgnoresFragment() {
let tabRefAboutHome = gBrowser.addTab("about:home?hello=firefox#aaa");
yield promiseTabLoaded(tabRefAboutHome);
let tabRefAboutMozilla = gBrowser.addTab("about:mozilla?hello=firefoxos#aaa");
yield promiseTabLoaded(tabRefAboutMozilla);
gBrowser.selectedTab = tabRefAboutMozilla;
switchTab("about:home?hello=firefox#bbb", false, { ignoreQueryString: true });
gBrowser.removeCurrentTab();
switchTab("about:home?hello=firefoxos#aaa", true, { ignoreQueryString: true });
is(tabRefAboutHome, gBrowser.selectedTab, "Selected tab should be the initial about:home tab");
cleanupTestTabs();
});
// Begin helpers // Begin helpers
function cleanupTestTabs() { function cleanupTestTabs() {

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

@ -627,7 +627,7 @@ function openPreferences(paneID, extraArgs)
win = Services.ww.openWindow(null, Services.prefs.getCharPref("browser.chromeURL"), win = Services.ww.openWindow(null, Services.prefs.getCharPref("browser.chromeURL"),
"_blank", "chrome,dialog=no,all", windowArguments); "_blank", "chrome,dialog=no,all", windowArguments);
} else { } else {
newLoad = !win.switchToTabHavingURI(preferencesURL, true, {ignoreFragment: true}); newLoad = !win.switchToTabHavingURI(preferencesURL, true, { ignoreFragment: true, replaceQueryString: true });
browser = win.gBrowser.selectedBrowser; browser = win.gBrowser.selectedBrowser;
} }

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

@ -140,12 +140,24 @@ toolbarbutton.bookmark-item:not(.subviewbutton):not(:hover):not(:active):not([op
color: inherit; color: inherit;
} }
toolbarbutton.bookmark-item:not(.subviewbutton) {
-moz-appearance: none;
border: 1px solid transparent;
border-radius: 2px;
transition-property: background-color, border-color;
transition-duration: 150ms;
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([open]) {
background-color: var(--toolbarbutton-hover-background);
border-color: var(--toolbarbutton-hover-bordercolor);
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active, toolbarbutton.bookmark-item:not(.subviewbutton):hover:active,
toolbarbutton.bookmark-item[open="true"] { toolbarbutton.bookmark-item[open="true"] {
padding-top: 3px; background: var(--toolbarbutton-active-background);
padding-bottom: 1px; box-shadow: var(--toolbarbutton-active-boxshadow);
padding-inline-start: 4px; border-color: var(--toolbarbutton-active-bordercolor);
padding-inline-end: 2px;
} }
.bookmark-item > .toolbarbutton-icon, .bookmark-item > .toolbarbutton-icon,
@ -1670,7 +1682,7 @@ toolbarbutton.chevron {
list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important; list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important;
} }
toolbar[brighttext] toolbarbutton.chevron:not(:hover):not([open="true"]) { toolbar[brighttext] toolbarbutton.chevron {
list-style-image: url("chrome://global/skin/toolbar/chevron-inverted.png") !important; list-style-image: url("chrome://global/skin/toolbar/chevron-inverted.png") !important;
} }

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

@ -464,14 +464,20 @@ toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder { #personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
margin: 0; margin: 0;
padding: 2px 3px; padding: 2px 3px;
-moz-appearance: none;
border: 1px solid transparent;
} }
toolbarbutton.bookmark-item:not([disabled="true"]):not(.subviewbutton):hover:active, toolbarbutton.bookmark-item:not(.subviewbutton):hover:not([disabled="true"]):not([open]) {
border-color: var(--toolbarbutton-hover-bordercolor);
background: var(--toolbarbutton-hover-background);
}
toolbarbutton.bookmark-item:not(.subviewbutton):hover:active:not([disabled="true"]),
toolbarbutton.bookmark-item[open="true"] { toolbarbutton.bookmark-item[open="true"] {
padding-top: 3px; border-color: var(--toolbarbutton-active-bordercolor);
padding-bottom: 1px; box-shadow: var(--toolbarbutton-active-boxshadow);
padding-inline-start: 4px; background: var(--toolbarbutton-active-background);
padding-inline-end: 2px;
} }
.bookmark-item > .toolbarbutton-icon, .bookmark-item > .toolbarbutton-icon,

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

@ -147,18 +147,6 @@ if test "$CLANG_CXX"; then
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
fi fi
AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) actually is a C++ compiler])
AC_LANG_SAVE
AC_LANG_CPLUSPLUS
_SAVE_LIBS=$LIBS
LIBS=
AC_TRY_LINK([#include <new>], [int *foo = new int;],,
AC_MSG_RESULT([no])
AC_MSG_ERROR([$CXX $CXXFLAGS $LDFLAGS failed to compile and link a simple C++ source.]))
LIBS=$_SAVE_LIBS
AC_LANG_RESTORE
AC_MSG_RESULT([yes])
if test -n "$DEVELOPER_OPTIONS"; then if test -n "$DEVELOPER_OPTIONS"; then
MOZ_FORCE_GOLD=1 MOZ_FORCE_GOLD=1
fi fi

1
config/external/nss/Makefile.in поставляемый
Просмотреть файл

@ -117,6 +117,7 @@ export MOZ_DEBUG_SYMBOLS
DEFAULT_GMAKE_FLAGS = DEFAULT_GMAKE_FLAGS =
DEFAULT_GMAKE_FLAGS += CC='$(CC)' DEFAULT_GMAKE_FLAGS += CC='$(CC)'
DEFAULT_GMAKE_FLAGS += MT='$(MT)'
DEFAULT_GMAKE_FLAGS += SOURCE_MD_DIR=$(ABS_DIST) DEFAULT_GMAKE_FLAGS += SOURCE_MD_DIR=$(ABS_DIST)
DEFAULT_GMAKE_FLAGS += SOURCE_MDHEADERS_DIR=$(NSPR_INCLUDE_DIR) DEFAULT_GMAKE_FLAGS += SOURCE_MDHEADERS_DIR=$(NSPR_INCLUDE_DIR)
DEFAULT_GMAKE_FLAGS += DIST=$(ABS_DIST) DEFAULT_GMAKE_FLAGS += DIST=$(ABS_DIST)

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

@ -662,14 +662,14 @@ ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \ @if test -f $@.manifest; then \
if test -f '$(srcdir)/$@.manifest'; then \ if test -f '$(srcdir)/$@.manifest'; then \
echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \ echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
else \ else \
echo 'Embedding manifest from $@.manifest'; \ echo 'Embedding manifest from $@.manifest'; \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
fi; \ fi; \
elif test -f '$(srcdir)/$@.manifest'; then \ elif test -f '$(srcdir)/$@.manifest'; then \
echo 'Embedding manifest from $(srcdir)/$@.manifest'; \ echo 'Embedding manifest from $(srcdir)/$@.manifest'; \
mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' -OUTPUTRESOURCE:$@\;1; \
fi fi
endif # MSVC with manifest tool endif # MSVC with manifest tool
ifdef MOZ_PROFILE_GENERATE ifdef MOZ_PROFILE_GENERATE
@ -697,14 +697,14 @@ ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \ @if test -f $@.manifest; then \
if test -f '$(srcdir)/$@.manifest'; then \ if test -f '$(srcdir)/$@.manifest'; then \
echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \ echo 'Embedding manifest from $(srcdir)/$@.manifest and $@.manifest'; \
mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' $@.manifest -OUTPUTRESOURCE:$@\;1; \
else \ else \
echo 'Embedding manifest from $@.manifest'; \ echo 'Embedding manifest from $@.manifest'; \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
fi; \ fi; \
elif test -f '$(srcdir)/$@.manifest'; then \ elif test -f '$(srcdir)/$@.manifest'; then \
echo 'Embedding manifest from $(srcdir)/$@.manifest'; \ echo 'Embedding manifest from $(srcdir)/$@.manifest'; \
mt.exe -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$@.manifest' -OUTPUTRESOURCE:$@\;1; \
fi fi
endif # MSVC with manifest tool endif # MSVC with manifest tool
else else
@ -732,7 +732,7 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
ifdef MSMANIFEST_TOOL ifdef MSMANIFEST_TOOL
@if test -f $@.manifest; then \ @if test -f $@.manifest; then \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \ $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
rm -f $@.manifest; \ rm -f $@.manifest; \
fi fi
endif # MSVC with manifest tool endif # MSVC with manifest tool
@ -833,7 +833,7 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
ifdef MSMANIFEST_TOOL ifdef MSMANIFEST_TOOL
ifdef EMBED_MANIFEST_AT ifdef EMBED_MANIFEST_AT
@if test -f $@.manifest; then \ @if test -f $@.manifest; then \
mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \ $(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \
rm -f $@.manifest; \ rm -f $@.manifest; \
fi fi
endif # EMBED_MANIFEST_AT endif # EMBED_MANIFEST_AT

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

@ -11,5 +11,10 @@
"synthesizeKeyFromKeyTag": true, "synthesizeKeyFromKeyTag": true,
"TargetFactory": true, "TargetFactory": true,
"waitForTick": true, "waitForTick": true,
} },
"rules": {
// Tests can always import anything.
"mozilla/reject-some-requires": 0,
},
} }

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

@ -15,5 +15,7 @@
"block-scoped-var": 0, "block-scoped-var": 0,
// Allow run_test to be unused in xpcshell // Allow run_test to be unused in xpcshell
"no-unused-vars": [2, { "varsIgnorePattern": "run_test" }], "no-unused-vars": [2, { "varsIgnorePattern": "run_test" }],
// Tests can always import anything.
"mozilla/reject-some-requires": 0,
} }
} }

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

@ -0,0 +1,12 @@
{
// Extend from the devtools eslintrc.
"extends": "../../.eslintrc",
"rules": {
// The inspector is being migrated to HTML and cleaned of
// chrome-privileged code, so this rule disallows requiring chrome
// code. Some files in the inspector disable this rule still. The
// goal is to enable the rule globally on all files.
"mozilla/reject-some-requires": [2, "^(chrome|chrome:.*|resource:.*|devtools/server/.*|.*\\.jsm)$"],
},
}

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

@ -6,7 +6,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const Services = require("Services"); const Services = require("Services");
const promise = require("promise"); const promise = require("promise");
const FocusManager = Services.focus; const FocusManager = Services.focus;

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

@ -8,7 +8,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const ToolDefinitions = require("devtools/client/definitions").Tools; const ToolDefinitions = require("devtools/client/definitions").Tools;
const CssLogic = require("devtools/shared/inspector/css-logic"); const CssLogic = require("devtools/shared/inspector/css-logic");
@ -20,7 +22,9 @@ const {OutputParser} = require("devtools/client/shared/output-parser");
const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils"); const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");
const {createChild} = require("devtools/client/inspector/shared/utils"); const {createChild} = require("devtools/client/inspector/shared/utils");
const {gDevTools} = require("devtools/client/framework/devtools"); const {gDevTools} = require("devtools/client/framework/devtools");
/* eslint-disable mozilla/reject-some-requires */
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
const {getCssProperties} = require("devtools/shared/fronts/css-properties"); const {getCssProperties} = require("devtools/shared/fronts/css-properties");
loader.lazyRequireGetter(this, "overlays", loader.lazyRequireGetter(this, "overlays",

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

@ -6,7 +6,9 @@
const l10n = require("gcli/l10n"); const l10n = require("gcli/l10n");
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true); loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
/* eslint-disable mozilla/reject-some-requires */
const {EyeDropper, HighlighterEnvironment} = require("devtools/server/actors/highlighters"); const {EyeDropper, HighlighterEnvironment} = require("devtools/server/actors/highlighters");
/* eslint-enable mozilla/reject-some-requires */
const Telemetry = require("devtools/client/shared/telemetry"); const Telemetry = require("devtools/client/shared/telemetry");
exports.items = [{ exports.items = [{

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

@ -8,7 +8,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
var Services = require("Services"); var Services = require("Services");
var promise = require("promise"); var promise = require("promise");

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

@ -4,7 +4,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const promise = require("promise"); const promise = require("promise");
const {Task} = require("devtools/shared/task"); const {Task} = require("devtools/shared/task");

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

@ -6,7 +6,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {Task} = require("devtools/shared/task"); const {Task} = require("devtools/shared/task");
const {InplaceEditor, editableItem} = const {InplaceEditor, editableItem} =
require("devtools/client/shared/inplace-editor"); require("devtools/client/shared/inplace-editor");

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

@ -7,7 +7,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
// Page size for pageup/pagedown // Page size for pageup/pagedown
const PAGE_SIZE = 10; const PAGE_SIZE = 10;
@ -54,7 +56,9 @@ const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const {template} = require("devtools/shared/gcli/templater"); const {template} = require("devtools/shared/gcli/templater");
const nodeConstants = require("devtools/shared/dom-node-constants"); const nodeConstants = require("devtools/shared/dom-node-constants");
const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants"); const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
/* eslint-disable mozilla/reject-some-requires */
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
loader.lazyRequireGetter(this, "CSS", "CSS"); loader.lazyRequireGetter(this, "CSS", "CSS");
loader.lazyGetter(this, "AutocompletePopup", () => { loader.lazyGetter(this, "AutocompletePopup", () => {

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

@ -6,7 +6,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const promise = require("promise"); const promise = require("promise");
const CssLogic = require("devtools/shared/inspector/css-logic"); const CssLogic = require("devtools/shared/inspector/css-logic");
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles"); const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");

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

@ -6,10 +6,14 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {escapeCSSComment} = require("devtools/shared/css-parsing-utils"); const {escapeCSSComment} = require("devtools/shared/css-parsing-utils");
const {getCssProperties} = require("devtools/shared/fronts/css-properties"); const {getCssProperties} = require("devtools/shared/fronts/css-properties");
/* eslint-disable mozilla/reject-some-requires */
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
XPCOMUtils.defineLazyGetter(this, "domUtils", function () { XPCOMUtils.defineLazyGetter(this, "domUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);

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

@ -7,11 +7,15 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Cc, Ci} = require("chrome"); const {Cc, Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const promise = require("promise"); const promise = require("promise");
const defer = require("devtools/shared/defer"); const defer = require("devtools/shared/defer");
const Services = require("Services"); const Services = require("Services");
/* eslint-disable mozilla/reject-some-requires */
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
const {Task} = require("devtools/shared/task"); const {Task} = require("devtools/shared/task");
const {Tools} = require("devtools/client/definitions"); const {Tools} = require("devtools/client/definitions");
const {l10n} = require("devtools/shared/inspector/css-logic"); const {l10n} = require("devtools/shared/inspector/css-logic");

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

@ -4,8 +4,12 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
/* eslint-disable mozilla/reject-some-requires */
const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm"); const {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
const {l10n} = require("devtools/shared/inspector/css-logic"); const {l10n} = require("devtools/shared/inspector/css-logic");
const {ELEMENT_STYLE} = require("devtools/shared/specs/styles"); const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const {PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils"); const {PREF_ORIG_SOURCES} = require("devtools/client/styleeditor/utils");

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

@ -4,7 +4,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {l10n} = require("devtools/shared/inspector/css-logic"); const {l10n} = require("devtools/shared/inspector/css-logic");
const {getCssProperties} = require("devtools/shared/fronts/css-properties"); const {getCssProperties} = require("devtools/shared/fronts/css-properties");
const {InplaceEditor, editableField} = const {InplaceEditor, editableField} =

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

@ -6,7 +6,9 @@
"use strict"; "use strict";
/* eslint-disable mozilla/reject-some-requires */
const {Ci} = require("chrome"); const {Ci} = require("chrome");
/* eslint-enable mozilla/reject-some-requires */
const {parseDeclarations} = require("devtools/shared/css-parsing-utils"); const {parseDeclarations} = require("devtools/shared/css-parsing-utils");
const promise = require("promise"); const promise = require("promise");
const {getCSSLexer} = require("devtools/shared/css-lexer"); const {getCSSLexer} = require("devtools/shared/css-lexer");

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

@ -10,7 +10,9 @@ var Services = require("Services");
var EventEmitter = require("devtools/shared/event-emitter"); var EventEmitter = require("devtools/shared/event-emitter");
var Telemetry = require("devtools/client/shared/telemetry"); var Telemetry = require("devtools/client/shared/telemetry");
var { Task } = require("devtools/shared/task"); var { Task } = require("devtools/shared/task");
/* eslint-disable mozilla/reject-some-requires */
var { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); var { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
/* eslint-enable mozilla/reject-some-requires */
/** /**
* This object represents replacement for ToolSidebar * This object represents replacement for ToolSidebar

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

@ -1,7 +1,16 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- 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 - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="#aaa"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="#0b0b0b">
<style>
/* Use a fill that's visible on both light and dark themes for filter inputs */
#filterinput:target + #icon {
fill: #aaa;
}
</style>
<g id="filterinput"/>
<g id="icon">
<path fill-opacity=".3" d="M6.6 8.4c0-.6-1.7.3-1.7-.3 0-.4-1.7-2.7-1.7-2.7H13s-1.8 2-1.8 2.7c0 .3-2.1-.1-2.1.3v6.1H7s-.4-4.1-.4-6.1z"/> <path fill-opacity=".3" d="M6.6 8.4c0-.6-1.7.3-1.7-.3 0-.4-1.7-2.7-1.7-2.7H13s-1.8 2-1.8 2.7c0 .3-2.1-.1-2.1.3v6.1H7s-.4-4.1-.4-6.1z"/>
<path d="M2 2v2.3L4.7 9H6v5.4l2.1 1 1.8-.9V9h1.3L14 4.3V2H2zm11 2l-2.2 4H9v5.8l-.9.4-1.1-.5V8H5.2L3 4V3h10v1z"/> <path d="M2 2v2.3L4.7 9H6v5.4l2.1 1 1.8-.9V9h1.3L14 4.3V2H2zm11 2l-2.2 4H9v5.8l-.9.4-1.1-.5V8H5.2L3 4V3h10v1z"/>
</g>
</svg> </svg>

До

Ширина:  |  Высота:  |  Размер: 568 B

После

Ширина:  |  Высота:  |  Размер: 785 B

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

@ -364,7 +364,7 @@
} }
.devtools-filterinput { .devtools-filterinput {
background-image: var(--filter-image); background-image: url(images/filter.svg#filterinput);
} }
.devtools-searchinput:-moz-locale-dir(rtl), .devtools-searchinput:-moz-locale-dir(rtl),

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

@ -5,24 +5,46 @@
"use strict"; "use strict";
(function (factory) { (function (factory) {
// This file can be loaded in several different ways. It can be
// require()d, either from the main thread or from a worker thread;
// or it can be imported via Cu.import. These different forms
// explain some of the hairiness of this code.
//
// It's important for the devtools-as-html project that a require()
// on the main thread not use any chrome privileged APIs. Instead,
// the body of the main function can only require() (not Cu.import)
// modules that are available in the devtools content mode. This,
// plus the lack of |console| in workers, results in some gyrations
// in the definition of |console|.
if (this.module && module.id.indexOf("event-emitter") >= 0) { if (this.module && module.id.indexOf("event-emitter") >= 0) {
// require let console;
factory.call(this, require, exports, module); if (isWorker) {
console = {
error: () => {}
};
} else { } else {
// Cu.import console = this.console;
}
// require
factory.call(this, require, exports, module, console);
} else {
// Cu.import. This snippet implements a sort of miniature loader,
// which is responsible for appropriately translating require()
// requests from the client function. This code can use
// Cu.import, because it is never run in the devtools-in-content
// mode.
this.isWorker = false; this.isWorker = false;
const Cu = Components.utils;
let console = Cu.import("resource://gre/modules/Console.jsm", {}).console;
// Bug 1259045: This module is loaded early in firefox startup as a JSM, // Bug 1259045: This module is loaded early in firefox startup as a JSM,
// but it doesn't depends on any real module. We can save a few cycles // but it doesn't depends on any real module. We can save a few cycles
// and bytes by not loading Loader.jsm. // and bytes by not loading Loader.jsm.
let require = function (module) { let require = function (module) {
const Cu = Components.utils;
switch (module) { switch (module) {
case "devtools/shared/defer": case "devtools/shared/defer":
return Cu.import("resource://gre/modules/Promise.jsm", {}).Promise.defer; return Cu.import("resource://gre/modules/Promise.jsm", {}).Promise.defer;
case "Services": case "Services":
return Cu.import("resource://gre/modules/Services.jsm", {}).Services; return Cu.import("resource://gre/modules/Services.jsm", {}).Services;
case "resource://gre/modules/Console.jsm":
return Cu.import("resource://gre/modules/Console.jsm", {});
case "chrome": case "chrome":
return { return {
Cu, Cu,
@ -31,10 +53,13 @@
} }
return null; return null;
}; };
factory.call(this, require, this, { exports: this }); factory.call(this, require, this, { exports: this }, console);
this.EXPORTED_SYMBOLS = ["EventEmitter"]; this.EXPORTED_SYMBOLS = ["EventEmitter"];
} }
}).call(this, function (require, exports, module) { }).call(this, function (require, exports, module, console) {
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
// After this point the code may not use Cu.import, and should only
// require() modules that are "clean-for-content".
let EventEmitter = this.EventEmitter = function () {}; let EventEmitter = this.EventEmitter = function () {};
module.exports = EventEmitter; module.exports = EventEmitter;
@ -44,18 +69,13 @@
const defer = require("devtools/shared/defer"); const defer = require("devtools/shared/defer");
let loggingEnabled = true; let loggingEnabled = true;
let console = {};
if (!isWorker) { if (!isWorker) {
console = require("resource://gre/modules/Console.jsm").console;
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit"); loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
Services.prefs.addObserver("devtools.dump.emit", { Services.prefs.addObserver("devtools.dump.emit", {
observe: () => { observe: () => {
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit"); loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
} }
}, false); }, false);
} else {
// Workers can't load JSMs, so we can't import Console.jsm here.
console.error = () => {};
} }
/** /**

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

@ -507,19 +507,6 @@ KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const
return nullptr; return nullptr;
} }
bool
KeyframeEffectReadOnly::HasAnimationOfProperties(
const nsCSSProperty* aProperties,
size_t aPropertyCount) const
{
for (size_t i = 0; i < aPropertyCount; i++) {
if (HasAnimationOfProperty(aProperties[i])) {
return true;
}
}
return false;
}
#ifdef DEBUG #ifdef DEBUG
bool bool
SpecifiedKeyframeArraysAreEqual(const nsTArray<Keyframe>& aA, SpecifiedKeyframeArraysAreEqual(const nsTArray<Keyframe>& aA,

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

@ -294,8 +294,6 @@ public:
bool HasAnimationOfProperty(nsCSSProperty aProperty) const { bool HasAnimationOfProperty(nsCSSProperty aProperty) const {
return GetAnimationOfProperty(aProperty) != nullptr; return GetAnimationOfProperty(aProperty) != nullptr;
} }
bool HasAnimationOfProperties(const nsCSSProperty* aProperties,
size_t aPropertyCount) const;
const InfallibleTArray<AnimationProperty>& Properties() const { const InfallibleTArray<AnimationProperty>& Properties() const {
return mProperties; return mProperties;
} }

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

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>Bug 1272475 - scale function with an extreme large value</title>
<script>
function test() {
var div = document.createElement("div");
div.setAttribute("style", "width: 1px; height: 1px; " +
"background: red;");
document.body.appendChild(div);
div.animate([ { "transform": "scale(8)" },
{ "transform": "scale(9.5e+307)" },
{ "transform": "scale(32)" } ],
{ "duration": 1000, "fill": "both" });
}
</script>
</head>
<body onload="test()">
</body>
</html>

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

@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<title>Bug 1272475 - rotate function with an extreme large value</title>
<script>
function test() {
var div = document.createElement("div");
div.setAttribute("style", "width: 100px; height: 100px; " +
"background: red;");
document.body.appendChild(div);
div.animate([ { "transform": "rotate(8rad)" },
{ "transform": "rotate(9.5e+307rad)" },
{ "transform": "rotate(32rad)" } ],
{ "duration": 1000, "fill": "both" });
}
</script>
</head>
<body onload="test()">
</body>
</html>

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

@ -6,5 +6,7 @@ pref(dom.animations-api.core.enabled,true) load 1216842-3.html
pref(dom.animations-api.core.enabled,true) load 1216842-4.html pref(dom.animations-api.core.enabled,true) load 1216842-4.html
pref(dom.animations-api.core.enabled,true) load 1216842-5.html pref(dom.animations-api.core.enabled,true) load 1216842-5.html
pref(dom.animations-api.core.enabled,true) load 1216842-6.html pref(dom.animations-api.core.enabled,true) load 1216842-6.html
pref(dom.animations-api.core.enabled,true) load 1272475-1.html
pref(dom.animations-api.core.enabled,true) load 1272475-2.html
pref(dom.animations-api.core.enabled,true) load 1278485-1.html pref(dom.animations-api.core.enabled,true) load 1278485-1.html
pref(dom.animations-api.core.enabled,true) load 1277272-1.html pref(dom.animations-api.core.enabled,true) load 1277272-1.html

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

@ -41,6 +41,7 @@ support-files =
mozilla/file_document-timeline-origin-time-range.html mozilla/file_document-timeline-origin-time-range.html
mozilla/file_hide_and_show.html mozilla/file_hide_and_show.html
mozilla/file_partial_keyframes.html mozilla/file_partial_keyframes.html
mozilla/file_transform_limits.html
style/file_animation-seeking-with-current-time.html style/file_animation-seeking-with-current-time.html
style/file_animation-seeking-with-start-time.html style/file_animation-seeking-with-start-time.html
testcommon.js testcommon.js
@ -89,5 +90,6 @@ skip-if = (toolkit == 'gonk' && debug)
[mozilla/test_hide_and_show.html] [mozilla/test_hide_and_show.html]
[mozilla/test_partial_keyframes.html] [mozilla/test_partial_keyframes.html]
[mozilla/test_set-easing.html] [mozilla/test_set-easing.html]
[mozilla/test_transform_limits.html]
[style/test_animation-seeking-with-current-time.html] [style/test_animation-seeking-with-current-time.html]
[style/test_animation-seeking-with-start-time.html] [style/test_animation-seeking-with-start-time.html]

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

@ -0,0 +1,55 @@
<!doctype html>
<meta charset=utf-8>
<script src="../testcommon.js"></script>
<body>
<script>
'use strict';
// We clamp +infinity or -inifinity value in floating point to
// maximum floating point value or -maximum floating point value.
const max_float = 3.40282e+38;
test(function(t) {
var div = addDiv(t);
div.style = "width: 1px; height: 1px;";
var anim = div.animate([ { transform: 'scale(1)' },
{ transform: 'scale(3.5e+38)'},
{ transform: 'scale(3)' } ], 100 * MS_PER_SEC);
anim.pause();
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).transform,
'matrix(' + max_float + ', 0, 0, ' + max_float + ', 0, 0)');
}, 'Test that the parameter of transform scale is clamped' );
test(function(t) {
var div = addDiv(t);
div.style = "width: 1px; height: 1px;";
var anim = div.animate([ { transform: 'translate(1px)' },
{ transform: 'translate(3.5e+38px)'},
{ transform: 'translate(3px)' } ], 100 * MS_PER_SEC);
anim.pause();
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).transform,
'matrix(1, 0, 0, 1, ' + max_float + ', 0)');
}, 'Test that the parameter of transform translate is clamped' );
test(function(t) {
var div = addDiv(t);
div.style = "width: 1px; height: 1px;";
var anim = div.animate([ { transform: 'matrix(0.5, 0, 0, 0.5, 0, 0)' },
{ transform: 'matrix(2, 0, 0, 2, 3.5e+38, 0)'},
{ transform: 'matrix(0, 2, 0, -2, 0, 0)' } ],
100 * MS_PER_SEC);
anim.pause();
anim.currentTime = 50 * MS_PER_SEC;
assert_equals(getComputedStyle(div).transform,
'matrix(2, 0, 0, 2, ' + max_float + ', 0)');
}, 'Test that the parameter of transform matrix is clamped' );
done();
</script>
</body>

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

@ -0,0 +1,14 @@
<!doctype html>
<meta charset=utf-8>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
'use strict';
setup({explicit_done: true});
SpecialPowers.pushPrefEnv(
{ "set": [["dom.animations-api.core.enabled", true]]},
function() {
window.open("file_transform_limits.html");
});
</script>

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

@ -293,7 +293,7 @@ MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -323,9 +323,8 @@ MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown || if (IsShutdown() ||
!mDecoderStateMachine || !mDecoderStateMachine ||
mPlayState == PLAY_STATE_SHUTDOWN ||
!mOwner->GetVideoFrameContainer() || !mOwner->GetVideoFrameContainer() ||
(mOwner->GetMediaElement() && mOwner->GetMediaElement()->IsBeingDestroyed()) || (mOwner->GetMediaElement() && mOwner->GetMediaElement()->IsBeingDestroyed()) ||
!mDormantSupported) !mDormantSupported)
@ -372,20 +371,8 @@ MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
return; return;
} }
if (mIsDormant) { DECODER_LOG("UpdateDormantState() %s DORMANT state", mIsDormant ? "entering" : "exiting");
DECODER_LOG("UpdateDormantState() entering DORMANT state"); mDecoderStateMachine->DispatchSetDormant(mIsDormant);
// enter dormant state
mDecoderStateMachine->DispatchSetDormant(true);
if (IsEnded()) {
mWasEndedWhenEnteredDormant = true;
}
mNextState = mPlayState;
ChangeState(PLAY_STATE_LOADING);
} else {
DECODER_LOG("UpdateDormantState() leaving DORMANT state");
// exit dormant state
mDecoderStateMachine->DispatchSetDormant(false);
}
} }
void void
@ -407,7 +394,7 @@ MediaDecoder::StartDormantTimer()
} }
if (mIsHeuristicDormant || if (mIsHeuristicDormant ||
mShuttingDown || IsShutdown() ||
mIsVisible || mIsVisible ||
(mPlayState != PLAY_STATE_PAUSED && (mPlayState != PLAY_STATE_PAUSED &&
!IsEnded())) !IsEnded()))
@ -437,12 +424,13 @@ void
MediaDecoder::Pause() MediaDecoder::Pause()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mPlayState == PLAY_STATE_LOADING || if (IsShutdown()) {
IsEnded()) { return;
}
if (mPlayState == PLAY_STATE_LOADING || IsEnded()) {
mNextState = PLAY_STATE_PAUSED; mNextState = PLAY_STATE_PAUSED;
return; return;
} }
ChangeState(PLAY_STATE_PAUSED); ChangeState(PLAY_STATE_PAUSED);
} }
@ -488,13 +476,13 @@ void
MediaDecoder::SetInfinite(bool aInfinite) MediaDecoder::SetInfinite(bool aInfinite)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
mInfiniteStream = aInfinite; mInfiniteStream = aInfinite;
DurationChanged(); DurationChanged();
} }
bool bool
MediaDecoder::IsInfinite() MediaDecoder::IsInfinite() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return mInfiniteStream; return mInfiniteStream;
@ -516,13 +504,11 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
, mVideoFrameContainer(aOwner->GetVideoFrameContainer()) , mVideoFrameContainer(aOwner->GetVideoFrameContainer())
, mPlaybackStatistics(new MediaChannelStatistics()) , mPlaybackStatistics(new MediaChannelStatistics())
, mPinnedForSeek(false) , mPinnedForSeek(false)
, mShuttingDown(false)
, mPausedForPlaybackRateNull(false) , mPausedForPlaybackRateNull(false)
, mMinimizePreroll(false) , mMinimizePreroll(false)
, mMediaTracksConstructed(false) , mMediaTracksConstructed(false)
, mFiredMetadataLoaded(false) , mFiredMetadataLoaded(false)
, mIsDormant(false) , mIsDormant(false)
, mWasEndedWhenEnteredDormant(false)
, mIsHeuristicDormantSupported( , mIsHeuristicDormantSupported(
Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)) Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
, mHeuristicDormantTimeout( , mHeuristicDormantTimeout(
@ -620,12 +606,10 @@ MediaDecoder::Shutdown()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
mShuttingDown = true;
// Unwatch all watch targets to prevent further notifications. // Unwatch all watch targets to prevent further notifications.
mWatchManager.Shutdown(); mWatchManager.Shutdown();
@ -820,7 +804,7 @@ nsresult
MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aPromise /*=nullptr*/) MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aPromise /*=nullptr*/)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE(!mShuttingDown, NS_ERROR_FAILURE); NS_ENSURE_TRUE(!IsShutdown(), NS_ERROR_FAILURE);
UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */); UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
@ -830,7 +814,6 @@ MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType, dom::Promise* aProm
int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds(); int64_t timeUsecs = TimeUnit::FromSeconds(aTime).ToMicroseconds();
mLogicalPosition = aTime; mLogicalPosition = aTime;
mWasEndedWhenEnteredDormant = false;
mLogicallySeeking = true; mLogicallySeeking = true;
SeekTarget target = SeekTarget(timeUsecs, aSeekType); SeekTarget target = SeekTarget(timeUsecs, aSeekType);
@ -924,7 +907,7 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility) MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d", DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
@ -997,7 +980,7 @@ MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility) MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mIsDormant=%d", DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mIsDormant=%d",
aInfo->mAudio.mChannels, aInfo->mAudio.mRate, aInfo->mAudio.mChannels, aInfo->mAudio.mRate,
@ -1030,7 +1013,7 @@ nsresult
MediaDecoder::FinishDecoderSetup(MediaResource* aResource) MediaDecoder::FinishDecoderSetup(MediaResource* aResource)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
HTMLMediaElement* element = mOwner->GetMediaElement(); HTMLMediaElement* element = mOwner->GetMediaElement();
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
element->FinishDecoderSetup(this, aResource); element->FinishDecoderSetup(this, aResource);
@ -1041,7 +1024,7 @@ void
MediaDecoder::ResetConnectionState() MediaDecoder::ResetConnectionState()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
// Notify the media element that connection gets lost. // Notify the media element that connection gets lost.
mOwner->ResetConnectionState(); mOwner->ResetConnectionState();
@ -1056,7 +1039,7 @@ void
MediaDecoder::NetworkError() MediaDecoder::NetworkError()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) if (IsShutdown())
return; return;
mOwner->NetworkError(); mOwner->NetworkError();
@ -1067,7 +1050,7 @@ void
MediaDecoder::DecodeError() MediaDecoder::DecodeError()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) if (IsShutdown())
return; return;
mOwner->DecodeError(); mOwner->DecodeError();
@ -1092,14 +1075,14 @@ bool
MediaDecoder::IsEndedOrShutdown() const MediaDecoder::IsEndedOrShutdown() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return IsEnded() || mPlayState == PLAY_STATE_SHUTDOWN; return IsEnded() || IsShutdown();
} }
bool bool
MediaDecoder::OwnerHasError() const MediaDecoder::OwnerHasError() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return mShuttingDown || mOwner->HasError(); return IsShutdown() || mOwner->HasError();
} }
class MediaElementGMPCrashHelper : public GMPCrashHelper class MediaElementGMPCrashHelper : public GMPCrashHelper
@ -1134,8 +1117,14 @@ bool
MediaDecoder::IsEnded() const MediaDecoder::IsEnded() const
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
return mPlayState == PLAY_STATE_ENDED || return mPlayState == PLAY_STATE_ENDED;
(mWasEndedWhenEnteredDormant && (mPlayState != PLAY_STATE_SHUTDOWN)); }
bool
MediaDecoder::IsShutdown() const
{
MOZ_ASSERT(NS_IsMainThread());
return mPlayState == PLAY_STATE_SHUTDOWN;
} }
void void
@ -1143,7 +1132,7 @@ MediaDecoder::PlaybackEnded()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown || if (IsShutdown() ||
mLogicallySeeking || mLogicallySeeking ||
mPlayState == PLAY_STATE_LOADING) { mPlayState == PLAY_STATE_LOADING) {
return; return;
@ -1220,7 +1209,7 @@ void
MediaDecoder::NotifySuspendedStatusChanged() MediaDecoder::NotifySuspendedStatusChanged()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
if (mResource) { if (mResource) {
bool suspended = mResource->IsSuspendedByCache(); bool suspended = mResource->IsSuspendedByCache();
mOwner->NotifySuspendedByCache(suspended); mOwner->NotifySuspendedByCache(suspended);
@ -1231,7 +1220,7 @@ void
MediaDecoder::NotifyBytesDownloaded() MediaDecoder::NotifyBytesDownloaded()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
UpdatePlaybackRate(); UpdatePlaybackRate();
@ -1242,7 +1231,7 @@ void
MediaDecoder::NotifyDownloadEnded(nsresult aStatus) MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus); DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
@ -1268,7 +1257,7 @@ void
MediaDecoder::NotifyPrincipalChanged() MediaDecoder::NotifyPrincipalChanged()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal(); nsCOMPtr<nsIPrincipal> newPrincipal = GetCurrentPrincipal();
mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal); mMediaPrincipalHandle = MakePrincipalHandle(newPrincipal);
mOwner->NotifyDecoderPrincipalChanged(); mOwner->NotifyDecoderPrincipalChanged();
@ -1278,7 +1267,7 @@ void
MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
if (mIgnoreProgressData) { if (mIgnoreProgressData) {
return; return;
@ -1297,7 +1286,7 @@ MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
mSeekRequest.Complete(); mSeekRequest.Complete();
if (mShuttingDown) if (IsShutdown())
return; return;
bool fireEnded = false; bool fireEnded = false;
@ -1337,7 +1326,7 @@ void
MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility) MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) if (IsShutdown())
return; return;
if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) { if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
@ -1349,15 +1338,12 @@ void
MediaDecoder::ChangeState(PlayState aState) MediaDecoder::ChangeState(PlayState aState)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsShutdown(), "SHUTDOWN is the final state.");
if (mNextState == aState) { if (mNextState == aState) {
mNextState = PLAY_STATE_PAUSED; mNextState = PLAY_STATE_PAUSED;
} }
if (mPlayState == PLAY_STATE_SHUTDOWN) {
return;
}
DECODER_LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState)); DECODER_LOG("ChangeState %s => %s", PlayStateStr(), ToPlayStateStr(aState));
mPlayState = aState; mPlayState = aState;
@ -1376,7 +1362,7 @@ void
MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility) MediaDecoder::UpdateLogicalPositionInternal(MediaDecoderEventVisibility aEventVisibility)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -1401,7 +1387,7 @@ MediaDecoder::DurationChanged()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -1681,7 +1667,7 @@ MediaDecoder::NotifyDataArrived() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
// Don't publish events since task queues might be shutting down. // Don't publish events since task queues might be shutting down.
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -1699,7 +1685,7 @@ void
MediaDecoder::FireTimeUpdate() MediaDecoder::FireTimeUpdate()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
mOwner->FireTimeUpdate(true); mOwner->FireTimeUpdate(true);
@ -1879,7 +1865,7 @@ MediaDecoder::GetOwner()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
// mOwner is valid until shutdown. // mOwner is valid until shutdown.
return !mShuttingDown ? mOwner : nullptr; return !IsShutdown() ? mOwner : nullptr;
} }
void void
@ -1887,7 +1873,7 @@ MediaDecoder::ConstructMediaTracks()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown || mMediaTracksConstructed || !mInfo) { if (IsShutdown() || mMediaTracksConstructed || !mInfo) {
return; return;
} }
@ -1923,7 +1909,7 @@ MediaDecoder::RemoveMediaTracks()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -1964,16 +1950,16 @@ void
MediaDecoder::DumpDebugInfo() MediaDecoder::DumpDebugInfo()
{ {
DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, " DUMP_LOG("metadata: channels=%u rate=%u hasAudio=%d hasVideo=%d, "
"state: mPlayState=%s mIsDormant=%d, mShuttingDown=%d", "state: mPlayState=%s mIsDormant=%d, IsShutdown()=%d",
mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0, mInfo ? mInfo->mAudio.mChannels : 0, mInfo ? mInfo->mAudio.mRate : 0,
mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0, mInfo ? mInfo->HasAudio() : 0, mInfo ? mInfo->HasVideo() : 0,
PlayStateStr(), mIsDormant, mShuttingDown); PlayStateStr(), mIsDormant, IsShutdown());
nsString str; nsString str;
GetMozDebugReaderData(str); GetMozDebugReaderData(str);
DUMP_LOG("reader data:\n%s", NS_ConvertUTF16toUTF8(str).get()); DUMP_LOG("reader data:\n%s", NS_ConvertUTF16toUTF8(str).get());
if (!mShuttingDown && GetStateMachine()) { if (!IsShutdown() && GetStateMachine()) {
GetStateMachine()->DumpDebugInfo(); GetStateMachine()->DumpDebugInfo();
} }
} }
@ -1981,7 +1967,7 @@ MediaDecoder::DumpDebugInfo()
void void
MediaDecoder::NotifyAudibleStateChanged() MediaDecoder::NotifyAudibleStateChanged()
{ {
MOZ_ASSERT(!mShuttingDown); MOZ_ASSERT(!IsShutdown());
mOwner->SetAudibleState(mIsAudioDataAudible); mOwner->SetAudibleState(mIsAudioDataAudible);
} }

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

@ -220,7 +220,7 @@ public:
virtual double GetDuration(); virtual double GetDuration();
// Return true if the stream is infinite (see SetInfinite). // Return true if the stream is infinite (see SetInfinite).
virtual bool IsInfinite(); bool IsInfinite() const;
// Called by MediaResource when some data has been received. // Called by MediaResource when some data has been received.
// Call on the main thread only. // Call on the main thread only.
@ -232,12 +232,12 @@ public:
// Return true if we are currently seeking in the media resource. // Return true if we are currently seeking in the media resource.
// Call on the main thread only. // Call on the main thread only.
virtual bool IsSeeking() const; bool IsSeeking() const;
// Return true if the decoder has reached the end of playback or the decoder // Return true if the decoder has reached the end of playback or the decoder
// has shutdown. // has shutdown.
// Call on the main thread only. // Call on the main thread only.
virtual bool IsEndedOrShutdown() const; bool IsEndedOrShutdown() const;
// Return true if the MediaDecoderOwner's error attribute is not null. // Return true if the MediaDecoderOwner's error attribute is not null.
// If the MediaDecoder is shutting down, OwnerHasError will return true. // If the MediaDecoder is shutting down, OwnerHasError will return true.
@ -493,7 +493,7 @@ private:
void UpdateReadyState() void UpdateReadyState()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!mShuttingDown) { if (!IsShutdown()) {
mOwner->UpdateReadyState(); mOwner->UpdateReadyState();
} }
} }
@ -528,6 +528,8 @@ protected:
// Return true if the decoder has reached the end of playback // Return true if the decoder has reached the end of playback
bool IsEnded() const; bool IsEnded() const;
bool IsShutdown() const;
// Called by the state machine to notify the decoder that the duration // Called by the state machine to notify the decoder that the duration
// has changed. // has changed.
void DurationChanged(); void DurationChanged();
@ -682,12 +684,6 @@ protected:
// while seeking. // while seeking.
bool mPinnedForSeek; bool mPinnedForSeek;
// True if the decoder is being shutdown. At this point all events that
// are currently queued need to return immediately to prevent javascript
// being run that operates on the element and decoder during shutdown.
// Read/Write from the main thread only.
bool mShuttingDown;
// True if the playback is paused because the playback rate member is 0.0. // True if the playback is paused because the playback rate member is 0.0.
bool mPausedForPlaybackRateNull; bool mPausedForPlaybackRateNull;
@ -715,12 +711,6 @@ protected:
// True if MediaDecoder is in dormant state. // True if MediaDecoder is in dormant state.
bool mIsDormant; bool mIsDormant;
// True if MediaDecoder was PLAY_STATE_ENDED state, when entering to dormant.
// When MediaCodec is in dormant during PLAY_STATE_ENDED state, PlayState
// becomes different from PLAY_STATE_ENDED. But the MediaDecoder need to act
// as in PLAY_STATE_ENDED state to MediaDecoderOwner.
bool mWasEndedWhenEnteredDormant;
// True if heuristic dormant is supported. // True if heuristic dormant is supported.
const bool mIsHeuristicDormantSupported; const bool mIsHeuristicDormantSupported;

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

@ -138,7 +138,7 @@ MediaOmxCommonDecoder::ResumeStateMachine()
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
DECODER_LOG(LogLevel::Debug, ("%s current time %f", __PRETTY_FUNCTION__, mLogicalPosition)); DECODER_LOG(LogLevel::Debug, ("%s current time %f", __PRETTY_FUNCTION__, mLogicalPosition));
if (mShuttingDown) { if (IsShutdown()) {
return; return;
} }
@ -156,8 +156,6 @@ MediaOmxCommonDecoder::ResumeStateMachine()
// Call Seek of MediaDecoderStateMachine to suppress seek events. // Call Seek of MediaDecoderStateMachine to suppress seek events.
GetStateMachine()->InvokeSeek(target); GetStateMachine()->InvokeSeek(target);
mNextState = mPlayState;
ChangeState(PLAY_STATE_LOADING);
// exit dormant state // exit dormant state
GetStateMachine()->DispatchSetDormant(false); GetStateMachine()->DispatchSetDormant(false);
UpdateLogicalPosition(); UpdateLogicalPosition();

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

@ -795,6 +795,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'IccChangeEvent.webidl', 'IccChangeEvent.webidl',
'ImageCaptureErrorEvent.webidl', 'ImageCaptureErrorEvent.webidl',
'MediaStreamEvent.webidl', 'MediaStreamEvent.webidl',
'MediaStreamTrackEvent.webidl',
'MozCellBroadcastEvent.webidl', 'MozCellBroadcastEvent.webidl',
'MozClirModeEvent.webidl', 'MozClirModeEvent.webidl',
'MozContactChangeEvent.webidl', 'MozContactChangeEvent.webidl',
@ -836,7 +837,6 @@ GENERATED_EVENTS_WEBIDL_FILES = [
if CONFIG['MOZ_WEBRTC']: if CONFIG['MOZ_WEBRTC']:
GENERATED_EVENTS_WEBIDL_FILES += [ GENERATED_EVENTS_WEBIDL_FILES += [
'MediaStreamTrackEvent.webidl',
'RTCDataChannelEvent.webidl', 'RTCDataChannelEvent.webidl',
'RTCPeerConnectionIceEvent.webidl', 'RTCPeerConnectionIceEvent.webidl',
'RTCTrackEvent.webidl', 'RTCTrackEvent.webidl',

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

@ -29,7 +29,6 @@
#define MOZ_GL_DEBUG 1 #define MOZ_GL_DEBUG 1
#endif #endif
#include "../../mfbt/Maybe.h"
#include "../../mfbt/RefPtr.h" #include "../../mfbt/RefPtr.h"
#include "../../mfbt/UniquePtr.h" #include "../../mfbt/UniquePtr.h"
@ -3303,13 +3302,6 @@ public:
GLuint GetFB(); GLuint GetFB();
/*
* Retrieves the size of the native windowing system drawable.
*/
virtual Maybe<gfx::IntSize> GetTargetSize() {
return Maybe<gfx::IntSize>();
};
private: private:
void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { void GetShaderPrecisionFormatNonES2(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
switch (precisiontype) { switch (precisiontype) {

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

@ -66,8 +66,6 @@ public:
// Undoes the effect of a drawable override. // Undoes the effect of a drawable override.
bool RestoreDrawable(); bool RestoreDrawable();
virtual Maybe<gfx::IntSize> GetTargetSize() override;
private: private:
friend class GLContextProviderGLX; friend class GLContextProviderGLX;

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

@ -987,20 +987,6 @@ GLContextGLX::SwapBuffers()
return true; return true;
} }
Maybe<gfx::IntSize>
GLContextGLX::GetTargetSize()
{
unsigned int width = 0, height = 0;
Window root;
int x, y;
unsigned int border, depth;
XGetGeometry(mDisplay, mDrawable, &root, &x, &y, &width, &height,
&border, &depth);
Maybe<gfx::IntSize> size;
size.emplace(width, height);
return size;
}
bool bool
GLContextGLX::OverrideDrawable(GLXDrawable drawable) GLContextGLX::OverrideDrawable(GLXDrawable drawable)
{ {

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

@ -6,6 +6,7 @@
#include "CompositingRenderTargetOGL.h" #include "CompositingRenderTargetOGL.h"
#include "GLContext.h" #include "GLContext.h"
#include "GLReadTexImageHelper.h" #include "GLReadTexImageHelper.h"
#include "ScopedGLHelpers.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
namespace mozilla { namespace mozilla {
@ -69,7 +70,9 @@ CompositingRenderTargetOGL::BindRenderTarget()
} }
if (needsClear) { if (needsClear) {
mGL->fScissor(0, 0, mInitParams.mSize.width, mInitParams.mSize.height); ScopedGLState scopedScissorTestState(mGL, LOCAL_GL_SCISSOR_TEST, true);
ScopedScissorRect autoScissorRect(mGL, 0, 0, mInitParams.mSize.width,
mInitParams.mSize.height);
mGL->fClearColor(0.0, 0.0, 0.0, 0.0); mGL->fClearColor(0.0, 0.0, 0.0, 0.0);
mGL->fClearDepth(0.0); mGL->fClearDepth(0.0);
mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);

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

@ -703,19 +703,9 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA); LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA);
mGLContext->fEnable(LOCAL_GL_BLEND); mGLContext->fEnable(LOCAL_GL_BLEND);
// Make sure SCISSOR is enabled before setting the render target, since the RT
// assumes scissor is enabled while it does clears.
mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
// Prefer the native windowing system's provided window size for the viewport.
IntSize viewportSize =
mGLContext->GetTargetSize().valueOr(mWidgetSize.ToUnknownSize());
if (viewportSize != mWidgetSize.ToUnknownSize()) {
mGLContext->fScissor(0, 0, viewportSize.width, viewportSize.height);
}
RefPtr<CompositingRenderTargetOGL> rt = RefPtr<CompositingRenderTargetOGL> rt =
CompositingRenderTargetOGL::RenderTargetForWindow(this, viewportSize); CompositingRenderTargetOGL::RenderTargetForWindow(this,
IntSize(width, height));
SetRenderTarget(rt); SetRenderTarget(rt);
#ifdef DEBUG #ifdef DEBUG
@ -1060,7 +1050,8 @@ CompositorOGL::DrawQuad(const Rect& aRect,
clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y); clipRect.MoveBy(mRenderOffset.x, mRenderOffset.y);
} }
gl()->fScissor(clipRect.x, FlipY(clipRect.y + clipRect.height), ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
ScopedScissorRect autoScissorRect(mGLContext, clipRect.x, FlipY(clipRect.y + clipRect.height),
clipRect.width, clipRect.height); clipRect.width, clipRect.height);
MaskType maskType; MaskType maskType;
@ -1501,21 +1492,13 @@ CompositorOGL::EndFrame()
return; return;
} }
mCurrentRenderTarget = nullptr;
if (mTexturePool) { if (mTexturePool) {
mTexturePool->EndFrame(); mTexturePool->EndFrame();
} }
// If our window size changed during composition, we should discard the frame.
// We don't need to worry about rescheduling a composite, as widget
// implementations handle this in their expose event listeners.
// See bug 1184534. TODO: implement this for single-buffered targets?
IntSize targetSize = mGLContext->GetTargetSize().valueOr(mViewportSize);
if (!(mCurrentRenderTarget->IsWindow() && targetSize != mViewportSize)) {
mGLContext->SwapBuffers(); mGLContext->SwapBuffers();
}
mCurrentRenderTarget = nullptr;
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
// Unbind all textures // Unbind all textures

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

@ -241,7 +241,8 @@ case "$target" in
dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool', dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
dnl not something else like "magnetic tape manipulation utility". dnl not something else like "magnetic tape manipulation utility".
MSMT_TOOL=`${MT-mt} 2>&1|grep 'Microsoft (R) Manifest Tool'` MT=${MT-mt.exe}
MSMT_TOOL=`${MT} 2>&1|grep 'Microsoft (R) Manifest Tool'`
if test -z "$MSMT_TOOL"; then if test -z "$MSMT_TOOL"; then
AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.]) AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
fi fi
@ -256,6 +257,7 @@ case "$target" in
MSMANIFEST_TOOL=1 MSMANIFEST_TOOL=1
unset MSMT_TOOL unset MSMT_TOOL
AC_SUBST(MT)
# Check linker version # Check linker version
_LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`

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

@ -823,7 +823,6 @@ XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
// Go ahead and create an XPCWrappedNative for this object. // Go ahead and create an XPCWrappedNative for this object.
AutoMarkingNativeInterfacePtr iface(cx); AutoMarkingNativeInterfacePtr iface(cx);
if (iid) {
if (Interface) if (Interface)
iface = *Interface; iface = *Interface;
@ -835,7 +834,6 @@ XPCConvert::NativeInterface2JSObject(MutableHandleValue d,
if (Interface) if (Interface)
*Interface = iface; *Interface = iface;
} }
}
RefPtr<XPCWrappedNative> wrapper; RefPtr<XPCWrappedNative> wrapper;
nsresult rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface, nsresult rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface,

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

@ -446,7 +446,7 @@ ActiveLayerTracker::IsStyleAnimated(nsDisplayListBuilder* aBuilder,
if (aProperty == eCSSProperty_transform && aFrame->Combines3DTransformWithAncestors()) { if (aProperty == eCSSProperty_transform && aFrame->Combines3DTransformWithAncestors()) {
return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty); return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty);
} }
return nsLayoutUtils::HasCurrentAnimationsForProperties(aFrame, &aProperty, 1); return nsLayoutUtils::HasCurrentAnimationOfProperty(aFrame, aProperty);
} }
/* static */ bool /* static */ bool

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

@ -2050,6 +2050,15 @@ FrameLayerBuilder::GetDebugSingleOldPaintedLayerForFrame(nsIFrame* aFrame)
return layer->AsPaintedLayer(); return layer->AsPaintedLayer();
} }
// Reset state that should not persist when a layer is recycled.
static void
ResetLayerStateForRecycling(Layer* aLayer) {
// Currently, this clears the mask layer and ancestor mask layers.
// Other cleanup may be added here.
aLayer->SetMaskLayer(nullptr);
aLayer->SetAncestorMaskLayers({});
}
already_AddRefed<ColorLayer> already_AddRefed<ColorLayer>
ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted) ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted)
{ {
@ -2057,7 +2066,7 @@ ContainerState::CreateOrRecycleColorLayer(PaintedLayer *aPainted)
static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData)); static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
RefPtr<ColorLayer> layer = data->mColorLayer; RefPtr<ColorLayer> layer = data->mColorLayer;
if (layer) { if (layer) {
layer->SetMaskLayer(nullptr); ResetLayerStateForRecycling(layer);
layer->ClearExtraDumpInfo(); layer->ClearExtraDumpInfo();
} else { } else {
// Create a new layer // Create a new layer
@ -2081,7 +2090,7 @@ ContainerState::CreateOrRecycleImageLayer(PaintedLayer *aPainted)
static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData)); static_cast<PaintedDisplayItemLayerUserData*>(aPainted->GetUserData(&gPaintedDisplayItemLayerUserData));
RefPtr<ImageLayer> layer = data->mImageLayer; RefPtr<ImageLayer> layer = data->mImageLayer;
if (layer) { if (layer) {
layer->SetMaskLayer(nullptr); ResetLayerStateForRecycling(layer);
layer->ClearExtraDumpInfo(); layer->ClearExtraDumpInfo();
} else { } else {
// Create a new layer // Create a new layer
@ -2268,8 +2277,7 @@ ContainerState::RecyclePaintedLayer(PaintedLayer* aLayer,
{ {
// Clear clip rect and mask layer so we don't accidentally stay clipped. // Clear clip rect and mask layer so we don't accidentally stay clipped.
// We will reapply any necessary clipping. // We will reapply any necessary clipping.
aLayer->SetMaskLayer(nullptr); ResetLayerStateForRecycling(aLayer);
aLayer->SetAncestorMaskLayers({});
aLayer->ClearExtraDumpInfo(); aLayer->ClearExtraDumpInfo();
PaintedDisplayItemLayerUserData* data = PaintedDisplayItemLayerUserData* data =
@ -5230,8 +5238,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER, NS_ASSERTION(oldLayer->GetType() == Layer::TYPE_CONTAINER,
"Wrong layer type"); "Wrong layer type");
containerLayer = static_cast<ContainerLayer*>(oldLayer); containerLayer = static_cast<ContainerLayer*>(oldLayer);
containerLayer->SetMaskLayer(nullptr); ResetLayerStateForRecycling(containerLayer);
containerLayer->SetAncestorMaskLayers({});
} }
} }
} }
@ -5417,7 +5424,7 @@ FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder,
// layer rendering. // layer rendering.
return nullptr; return nullptr;
} }
layer->SetMaskLayer(nullptr); ResetLayerStateForRecycling(layer);
return layer; return layer;
} }

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

@ -495,20 +495,6 @@ nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
); );
} }
bool
nsLayoutUtils::HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
const nsCSSProperty* aProperties,
size_t aPropertyCount)
{
return HasMatchingAnimations(aFrame,
[&aProperties, &aPropertyCount](KeyframeEffectReadOnly& aEffect)
{
return aEffect.IsCurrent() &&
aEffect.HasAnimationOfProperties(aProperties, aPropertyCount);
}
);
}
bool bool
nsLayoutUtils::HasRelevantAnimationOfProperty(const nsIFrame* aFrame, nsLayoutUtils::HasRelevantAnimationOfProperty(const nsIFrame* aFrame,
nsCSSProperty aProperty) nsCSSProperty aProperty)

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

@ -2245,14 +2245,6 @@ public:
*/ */
static bool HasCurrentTransitions(const nsIFrame* aFrame); static bool HasCurrentTransitions(const nsIFrame* aFrame);
/**
* Returns true if the frame has any current animations or transitions
* for any of the specified properties.
*/
static bool HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
const nsCSSProperty* aProperties,
size_t aPropertyCount);
/** /**
* Returns true if the frame has current or in-effect (i.e. in before phase, * Returns true if the frame has current or in-effect (i.e. in before phase,
* running or filling) animations or transitions for the * running or filling) animations or transitions for the

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

@ -1082,12 +1082,14 @@ AddCSSValueAngle(double aCoeff1, const nsCSSValue &aValue1,
{ {
if (aValue1.GetUnit() == aValue2.GetUnit()) { if (aValue1.GetUnit() == aValue2.GetUnit()) {
// To avoid floating point error, if the units match, maintain the unit. // To avoid floating point error, if the units match, maintain the unit.
aResult.SetFloatValue(aCoeff1 * aValue1.GetFloatValue() + aResult.SetFloatValue(
aCoeff2 * aValue2.GetFloatValue(), EnsureNotNan(aCoeff1 * aValue1.GetFloatValue() +
aCoeff2 * aValue2.GetFloatValue()),
aValue1.GetUnit()); aValue1.GetUnit());
} else { } else {
aResult.SetFloatValue(aCoeff1 * aValue1.GetAngleValueInRadians() + aResult.SetFloatValue(
aCoeff2 * aValue2.GetAngleValueInRadians(), EnsureNotNan(aCoeff1 * aValue1.GetAngleValueInRadians() +
aCoeff2 * aValue2.GetAngleValueInRadians()),
eCSSUnit_Radian); eCSSUnit_Radian);
} }
} }
@ -1254,7 +1256,7 @@ AddTransformScale(double aCoeff1, const nsCSSValue &aValue1,
float v1 = aValue1.GetFloatValue() - 1.0f, float v1 = aValue1.GetFloatValue() - 1.0f,
v2 = aValue2.GetFloatValue() - 1.0f; v2 = aValue2.GetFloatValue() - 1.0f;
float result = v1 * aCoeff1 + v2 * aCoeff2; float result = v1 * aCoeff1 + v2 * aCoeff2;
aResult.SetFloatValue(result + 1.0f, eCSSUnit_Number); aResult.SetFloatValue(EnsureNotNan(result + 1.0f), eCSSUnit_Number);
} }
/* static */ already_AddRefed<nsCSSValue::Array> /* static */ already_AddRefed<nsCSSValue::Array>

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

@ -15417,6 +15417,16 @@ CSSParserImpl::ParseFunctionInternals(const uint32_t aVariantMask[],
break; break;
} }
if (nsCSSValue::IsFloatUnit(newValue.GetUnit())) {
// Clamp infinity or -infinity values to max float or -max float to avoid
// calculations with infinity.
newValue.SetFloatValue(
mozilla::clamped(newValue.GetFloatValue(),
-std::numeric_limits<float>::max(),
std::numeric_limits<float>::max()),
newValue.GetUnit());
}
aOutput.AppendElement(newValue); aOutput.AppendElement(newValue);
if (ExpectSymbol(',', true)) { if (ExpectSymbol(',', true)) {

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

@ -413,9 +413,9 @@ void nsCSSValue::SetPercentValue(float aValue)
void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit) void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit)
{ {
MOZ_ASSERT(eCSSUnit_Number <= aUnit, "not a float value"); MOZ_ASSERT(IsFloatUnit(aUnit), "not a float value");
Reset(); Reset();
if (eCSSUnit_Number <= aUnit) { if (IsFloatUnit(aUnit)) {
mUnit = aUnit; mUnit = aUnit;
mValue.mFloat = aValue; mValue.mFloat = aValue;
MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));

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

@ -516,6 +516,8 @@ public:
{ return eCSSUnit_Point <= aUnit && aUnit <= eCSSUnit_Pixel; } { return eCSSUnit_Point <= aUnit && aUnit <= eCSSUnit_Pixel; }
bool IsPixelLengthUnit() const bool IsPixelLengthUnit() const
{ return IsPixelLengthUnit(mUnit); } { return IsPixelLengthUnit(mUnit); }
static bool IsFloatUnit(nsCSSUnit aUnit)
{ return eCSSUnit_Number <= aUnit; }
bool IsAngularUnit() const bool IsAngularUnit() const
{ return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; } { return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; }
bool IsFrequencyUnit() const bool IsFrequencyUnit() const

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

@ -4184,12 +4184,11 @@ inline uint32_t ListLength(const T* aList)
return len; return len;
} }
static already_AddRefed<nsCSSShadowArray>
GetShadowData(const nsCSSValueList* aList,
already_AddRefed<nsCSSShadowArray>
nsRuleNode::GetShadowData(const nsCSSValueList* aList,
nsStyleContext* aContext, nsStyleContext* aContext,
bool aIsBoxShadow, bool aIsBoxShadow,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions) RuleNodeCacheConditions& aConditions)
{ {
uint32_t arrayLength = ListLength(aList); uint32_t arrayLength = ListLength(aList);
@ -4213,13 +4212,13 @@ nsRuleNode::GetShadowData(const nsCSSValueList* aList,
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(), unitOK = SetCoord(arr->Item(0), tempCoord, nsStyleCoord(),
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY, SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
aContext, mPresContext, aConditions); aContext, aPresContext, aConditions);
NS_ASSERTION(unitOK, "unexpected unit"); NS_ASSERTION(unitOK, "unexpected unit");
item->mXOffset = tempCoord.GetCoordValue(); item->mXOffset = tempCoord.GetCoordValue();
unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(), unitOK = SetCoord(arr->Item(1), tempCoord, nsStyleCoord(),
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY, SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
aContext, mPresContext, aConditions); aContext, aPresContext, aConditions);
NS_ASSERTION(unitOK, "unexpected unit"); NS_ASSERTION(unitOK, "unexpected unit");
item->mYOffset = tempCoord.GetCoordValue(); item->mYOffset = tempCoord.GetCoordValue();
@ -4228,7 +4227,7 @@ nsRuleNode::GetShadowData(const nsCSSValueList* aList,
unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(), unitOK = SetCoord(arr->Item(2), tempCoord, nsStyleCoord(),
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY | SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY |
SETCOORD_CALC_CLAMP_NONNEGATIVE, SETCOORD_CALC_CLAMP_NONNEGATIVE,
aContext, mPresContext, aConditions); aContext, aPresContext, aConditions);
NS_ASSERTION(unitOK, "unexpected unit"); NS_ASSERTION(unitOK, "unexpected unit");
item->mRadius = tempCoord.GetCoordValue(); item->mRadius = tempCoord.GetCoordValue();
} else { } else {
@ -4239,7 +4238,7 @@ nsRuleNode::GetShadowData(const nsCSSValueList* aList,
if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) { if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) {
unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(), unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(),
SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY, SETCOORD_LENGTH | SETCOORD_CALC_LENGTH_ONLY,
aContext, mPresContext, aConditions); aContext, aPresContext, aConditions);
NS_ASSERTION(unitOK, "unexpected unit"); NS_ASSERTION(unitOK, "unexpected unit");
item->mSpread = tempCoord.GetCoordValue(); item->mSpread = tempCoord.GetCoordValue();
} else { } else {
@ -4249,7 +4248,7 @@ nsRuleNode::GetShadowData(const nsCSSValueList* aList,
if (arr->Item(4).GetUnit() != eCSSUnit_Null) { if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
item->mHasColor = true; item->mHasColor = true;
// 2nd argument can be bogus since inherit is not a valid color // 2nd argument can be bogus since inherit is not a valid color
unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor, unitOK = SetColor(arr->Item(4), 0, aPresContext, aContext, item->mColor,
aConditions); aConditions);
NS_ASSERTION(unitOK, "unexpected unit"); NS_ASSERTION(unitOK, "unexpected unit");
} }
@ -4452,7 +4451,7 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
textShadowValue->GetUnit() == eCSSUnit_ListDep) { textShadowValue->GetUnit() == eCSSUnit_ListDep) {
// List of arrays // List of arrays
text->mTextShadow = GetShadowData(textShadowValue->GetListValue(), text->mTextShadow = GetShadowData(textShadowValue->GetListValue(),
aContext, false, conditions); aContext, false, mPresContext, conditions);
} }
} }
@ -9549,8 +9548,8 @@ nsRuleNode::ComputeSVGData(void* aStartStruct,
COMPUTE_END_INHERITED(SVG, svg) COMPUTE_END_INHERITED(SVG, svg)
} }
already_AddRefed<nsStyleBasicShape> static already_AddRefed<nsStyleBasicShape>
nsRuleNode::GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue, GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsPresContext* aPresContext, nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions) RuleNodeCacheConditions& aConditions)
@ -9698,8 +9697,8 @@ nsRuleNode::GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
return basicShape.forget(); return basicShape.forget();
} }
void static void
nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath, SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
const nsCSSValue* aValue, const nsCSSValue* aValue,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsPresContext* aPresContext, nsPresContext* aPresContext,
@ -9740,8 +9739,8 @@ nsRuleNode::SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
} }
// Returns true if the nsStyleFilter was successfully set using the nsCSSValue. // Returns true if the nsStyleFilter was successfully set using the nsCSSValue.
bool static bool
nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter, SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
const nsCSSValue& aValue, const nsCSSValue& aValue,
nsStyleContext* aStyleContext, nsStyleContext* aStyleContext,
nsPresContext* aPresContext, nsPresContext* aPresContext,
@ -9773,6 +9772,7 @@ nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
filterFunction->Item(1).GetListValue(), filterFunction->Item(1).GetListValue(),
aStyleContext, aStyleContext,
false, false,
aPresContext,
aConditions); aConditions);
aStyleFilter->SetDropShadow(shadowArray); aStyleFilter->SetDropShadow(shadowArray);
return true; return true;
@ -10161,7 +10161,7 @@ nsRuleNode::ComputeEffectsData(void* aStartStruct,
case eCSSUnit_List: case eCSSUnit_List:
case eCSSUnit_ListDep: case eCSSUnit_ListDep:
effects->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(), effects->mBoxShadow = GetShadowData(boxShadowValue->GetListValue(),
aContext, true, conditions); aContext, true, mPresContext, conditions);
break; break;
default: default:

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

@ -783,27 +783,6 @@ protected:
inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID, inline RuleDetail CheckSpecifiedProperties(const nsStyleStructID aSID,
const nsRuleData* aRuleData); const nsRuleData* aRuleData);
already_AddRefed<nsCSSShadowArray>
GetShadowData(const nsCSSValueList* aList,
nsStyleContext* aContext,
bool aIsBoxShadow,
mozilla::RuleNodeCacheConditions& aConditions);
already_AddRefed<nsStyleBasicShape>
GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
mozilla::RuleNodeCacheConditions& aConditions);
bool SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter,
const nsCSSValue& aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
mozilla::RuleNodeCacheConditions& aConditions);
void SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath,
const nsCSSValue* aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
mozilla::RuleNodeCacheConditions& aConditions);
private: private:
nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent, nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,
nsIStyleRule* aRule, mozilla::SheetType aLevel, bool aIsImportant); nsIStyleRule* aRule, mozilla::SheetType aLevel, bool aIsImportant);

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

@ -364,4 +364,11 @@ public class AppConstants {
// Do nothing. // Do nothing.
//#endif //#endif
} }
public static final boolean MOZ_ANDROID_ACTIVITY_STREAM =
//#ifdef MOZ_ANDROID_ACTIVITY_STREAM
true;
//#else
false;
//#endif
} }

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

@ -2691,9 +2691,16 @@ public class BrowserApp extends GeckoApp
} }
if (mHomeScreen == null) { if (mHomeScreen == null) {
if (AppConstants.MOZ_ANDROID_ACTIVITY_STREAM) {
final ViewStub asStub = (ViewStub) findViewById(R.id.activity_stream_stub);
mHomeScreen = (HomeScreen) asStub.inflate();
} else {
final ViewStub homePagerStub = (ViewStub) findViewById(R.id.home_pager_stub); final ViewStub homePagerStub = (ViewStub) findViewById(R.id.home_pager_stub);
mHomeScreen = (HomePager) homePagerStub.inflate(); mHomeScreen = (HomeScreen) homePagerStub.inflate();
// For now these listeners are HomePager specific. In future we might want
// to have a more abstracted data storage, with one Bundle containing all
// relevant restore data.
mHomeScreen.setOnPanelChangeListener(new HomeScreen.OnPanelChangeListener() { mHomeScreen.setOnPanelChangeListener(new HomeScreen.OnPanelChangeListener() {
@Override @Override
public void onPanelSelected(String panelId) { public void onPanelSelected(String panelId) {
@ -2714,6 +2721,7 @@ public class BrowserApp extends GeckoApp
} }
} }
}); });
}
// Don't show the banner in guest mode. // Don't show the banner in guest mode.
if (!Restrictions.isUserRestricted()) { if (!Restrictions.isUserRestricted()) {

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

@ -0,0 +1,69 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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.gecko.home.activitystream;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.home.HomeBanner;
import org.mozilla.gecko.home.HomeFragment;
import org.mozilla.gecko.home.HomeScreen;
public class ActivityStream extends FrameLayout implements HomeScreen {
public ActivityStream(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean isVisible() {
// This is dependent on the loading state - currently we're a dumb panel so we're always
// "visible"
return true;
}
@Override
public void onToolbarFocusChange(boolean hasFocus) {
// We don't care: this is HomePager specific
}
@Override
public void showPanel(String panelId, Bundle restoreData) {
// We could use this to restore Panel data. In practice this isn't likely to be relevant for
// AS and can be ignore for now.
}
@Override
public void setOnPanelChangeListener(OnPanelChangeListener listener) {
// As with showPanel: not relevant yet, could be used for persistence (scroll position?)
}
@Override
public void setPanelStateChangeListener(HomeFragment.PanelStateChangeListener listener) {
// See setOnPanelChangeListener
}
@Override
public void setBanner(HomeBanner banner) {
// TODO: we should probably implement this to show snippets.
}
@Override
public void load(LoaderManager lm, FragmentManager fm, String panelId, Bundle restoreData,
PropertyAnimator animator) {
// Signal to load data from storage as needed, compare with HomePager
}
@Override
public void unload() {
// Signal to clear data that has been loaded, compare with HomePager
}
}

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

@ -78,9 +78,20 @@ public class TelemetryJSONFilePingStore extends TelemetryPingStore {
@WorkerThread // Writes to disk @WorkerThread // Writes to disk
public TelemetryJSONFilePingStore(final File storeDir, final String profileName) { public TelemetryJSONFilePingStore(final File storeDir, final String profileName) {
super(profileName); super(profileName);
if (storeDir.exists() && !storeDir.isDirectory()) {
// An alternative is to create a new directory, but we wouldn't
// be able to access it later so it's better to throw.
throw new IllegalStateException("Store dir unexpectedly exists & is not a directory - cannot continue");
}
this.storeDir = storeDir; this.storeDir = storeDir;
this.storeDir.mkdirs(); this.storeDir.mkdirs();
uuidFilenameFilter = new FilenameRegexFilter(UUIDUtil.UUID_PATTERN); uuidFilenameFilter = new FilenameRegexFilter(UUIDUtil.UUID_PATTERN);
if (!this.storeDir.canRead() || !this.storeDir.canWrite() || !this.storeDir.canExecute()) {
throw new IllegalStateException("Cannot read, write, or execute store dir: " +
this.storeDir.canRead() + " " + this.storeDir.canWrite() + " " + this.storeDir.canExecute());
}
} }
@VisibleForTesting File getPingFile(final String docID) { @VisibleForTesting File getPingFile(final String docID) {
@ -129,7 +140,15 @@ public class TelemetryJSONFilePingStore extends TelemetryPingStore {
@Override @Override
public ArrayList<TelemetryPing> getAllPings() { public ArrayList<TelemetryPing> getAllPings() {
final List<File> files = Arrays.asList(storeDir.listFiles(uuidFilenameFilter)); final File[] fileArray = storeDir.listFiles(uuidFilenameFilter);
if (fileArray == null) {
// Intentionally don't log all info for the store directory to prevent leaking the path.
Log.w(LOGTAG, "listFiles unexpectedly returned null - unable to retrieve pings. Debug: exists? " +
storeDir.exists() + "; directory? " + storeDir.isDirectory());
return new ArrayList<>(1);
}
final List<File> files = Arrays.asList(fileArray);
Collections.sort(files, fileLastModifiedComparator); // oldest to newest Collections.sort(files, fileLastModifiedComparator); // oldest to newest
final ArrayList<TelemetryPing> out = new ArrayList<>(files.size()); final ArrayList<TelemetryPing> out = new ArrayList<>(files.size());
for (final File file : files) { for (final File file : files) {

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

@ -401,6 +401,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'health/HealthRecorder.java', 'health/HealthRecorder.java',
'health/SessionInformation.java', 'health/SessionInformation.java',
'health/StubbedHealthRecorder.java', 'health/StubbedHealthRecorder.java',
'home/activitystream/ActivityStream.java',
'home/BookmarkFolderView.java', 'home/BookmarkFolderView.java',
'home/BookmarkScreenshotRow.java', 'home/BookmarkScreenshotRow.java',
'home/BookmarksListAdapter.java', 'home/BookmarksListAdapter.java',
@ -965,7 +966,8 @@ for var in ('MOZ_ANDROID_ANR_REPORTER', 'MOZ_LINKER_EXTRACT', 'MOZ_DEBUG',
'MOZ_ANDROID_DOWNLOADS_INTEGRATION', 'MOZ_INSTALL_TRACKING', 'MOZ_ANDROID_DOWNLOADS_INTEGRATION', 'MOZ_INSTALL_TRACKING',
'MOZ_ANDROID_GCM', 'MOZ_ANDROID_EXCLUDE_FONTS', 'MOZ_LOCALE_SWITCHER', 'MOZ_ANDROID_GCM', 'MOZ_ANDROID_EXCLUDE_FONTS', 'MOZ_LOCALE_SWITCHER',
'MOZ_ANDROID_BEAM', 'MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE', 'MOZ_ANDROID_BEAM', 'MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE',
'MOZ_SWITCHBOARD', 'MOZ_ANDROID_CUSTOM_TABS'): 'MOZ_SWITCHBOARD', 'MOZ_ANDROID_CUSTOM_TABS',
'MOZ_ANDROID_ACTIVITY_STREAM'):
if CONFIG[var]: if CONFIG[var]:
DEFINES[var] = 1 DEFINES[var] = 1

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

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mozilla.gecko.home.activitystream.ActivityStream xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<TextView
tools:ignore="HardcodedText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Activity Stream \\o/"
android:id="@+id/textView"
android:layout_gravity="center_horizontal"/>
</org.mozilla.gecko.home.activitystream.ActivityStream>

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

@ -66,6 +66,11 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"/> android:layout_height="match_parent"/>
<ViewStub android:id="@+id/activity_stream_stub"
android:layout="@layout/activity_stream"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ViewStub android:id="@+id/home_banner_stub" <ViewStub android:id="@+id/home_banner_stub"
android:layout="@layout/home_banner" android:layout="@layout/home_banner"
android:layout_width="match_parent" android:layout_width="match_parent"

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

@ -48,6 +48,13 @@ project_flag('MOZ_SWITCHBOARD',
help='Include Switchboard A/B framework on Android', help='Include Switchboard A/B framework on Android',
default=True) default=True)
option(env='MOZ_ANDROID_ACTIVITY_STREAM',
help='Enable Activity Stream on Android (replacing the default HomePager)',
default=False)
set_config('MOZ_ANDROID_ACTIVITY_STREAM',
depends_if('MOZ_ANDROID_ACTIVITY_STREAM')(lambda _: True))
option('--disable-android-apz', env='MOZ_ANDROID_APZ', option('--disable-android-apz', env='MOZ_ANDROID_APZ',
help='Disable the C++ async pan/zoom code and use the Java version instead') help='Disable the C++ async pan/zoom code and use the Java version instead')

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

@ -19,6 +19,7 @@ import org.mozilla.gecko.util.FileUtils;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@ -70,6 +71,33 @@ public class TestTelemetryJSONFilePingStore {
assertEquals("Temp dir contains one dir (the store dir)", 1, tempDir.getRoot().list().length); assertEquals("Temp dir contains one dir (the store dir)", 1, tempDir.getRoot().list().length);
} }
@Test(expected = IllegalStateException.class)
public void testConstructorStoreAlreadyExistsAsNonDirectory() throws Exception {
final File file = tempDir.newFile();
new TelemetryJSONFilePingStore(file, "profileName"); // expected to throw.
}
@Test(expected = IllegalStateException.class)
public void testConstructorDirIsNotReadable() throws Exception {
final File dir = tempDir.newFolder();
dir.setReadable(false);
new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
}
@Test(expected = IllegalStateException.class)
public void testConstructorDirIsNotWritable() throws Exception {
final File dir = tempDir.newFolder();
dir.setWritable(false);
new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
}
@Test(expected = IllegalStateException.class)
public void testConstructorDirIsNotExecutable() throws Exception {
final File dir = tempDir.newFolder();
dir.setExecutable(false);
new TelemetryJSONFilePingStore(dir, "profileName"); // expected to throw.
}
@Test @Test
public void testStorePingStoresCorrectData() throws Exception { public void testStorePingStoresCorrectData() throws Exception {
assertStoreFileCount(0); assertStoreFileCount(0);

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

@ -368,7 +368,8 @@ case "$target" in
dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool', dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
dnl not something else like "magnetic tape manipulation utility". dnl not something else like "magnetic tape manipulation utility".
MSMT_TOOL=`${MT-mt} 2>&1|grep 'Microsoft (R) Manifest Tool'` MT=${MT-mt.exe}
MSMT_TOOL=`${MT} 2>&1|grep 'Microsoft (R) Manifest Tool'`
if test -z "$MSMT_TOOL"; then if test -z "$MSMT_TOOL"; then
AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.]) AC_MSG_ERROR([Microsoft (R) Manifest Tool must be in your \$PATH.])
fi fi
@ -383,6 +384,7 @@ case "$target" in
MSMANIFEST_TOOL=1 MSMANIFEST_TOOL=1
unset MSMT_TOOL unset MSMT_TOOL
AC_SUBST(MT)
# Check linker version # Check linker version
_LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"` _LD_FULL_VERSION=`"${LD}" -v 2>&1 | sed -nre "$_MSVC_VER_FILTER"`

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

@ -0,0 +1,107 @@
# 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 bz2
import gzip
import stat
import tarfile
# 2016-01-01T00:00:00+0000
DEFAULT_MTIME = 1451606400
def create_tar_from_files(fp, files):
"""Create a tar file deterministically.
Receives a dict mapping names of files in the archive to local filesystem
paths.
The files will be archived and written to the passed file handle opened
for writing.
Only regular files can be written.
FUTURE accept mozpack.files classes for writing
FUTURE accept a filename argument (or create APIs to write files)
"""
with tarfile.open(name='', mode='w', fileobj=fp, dereference=True) as tf:
for archive_path, fs_path in sorted(files.items()):
ti = tf.gettarinfo(fs_path, archive_path)
if not ti.isreg():
raise ValueError('not a regular file: %s' % fs_path)
# Disallow setuid and setgid bits. This is an arbitrary restriction.
# However, since we set uid/gid to root:root, setuid and setgid
# would be a glaring security hole if the archive were
# uncompressed as root.
if ti.mode & (stat.S_ISUID | stat.S_ISGID):
raise ValueError('cannot add file with setuid or setgid set: '
'%s' % fs_path)
# Set uid, gid, username, and group as deterministic values.
ti.uid = 0
ti.gid = 0
ti.uname = ''
ti.gname = ''
# Set mtime to a constant value.
ti.mtime = DEFAULT_MTIME
with open(fs_path, 'rb') as fh:
tf.addfile(ti, fh)
def create_tar_gz_from_files(fp, files, filename=None, compresslevel=9):
"""Create a tar.gz file deterministically from files.
This is a glorified wrapper around ``create_tar_from_files`` that
adds gzip compression.
The passed file handle should be opened for writing in binary mode.
When the function returns, all data has been written to the handle.
"""
# Offset 3-7 in the gzip header contains an mtime. Pin it to a known
# value so output is deterministic.
gf = gzip.GzipFile(filename=filename or '', mode='wb', fileobj=fp,
compresslevel=compresslevel, mtime=DEFAULT_MTIME)
with gf:
create_tar_from_files(gf, files)
class _BZ2Proxy(object):
"""File object that proxies writes to a bz2 compressor."""
def __init__(self, fp, compresslevel=9):
self.fp = fp
self.compressor = bz2.BZ2Compressor(compresslevel=compresslevel)
self.pos = 0
def tell(self):
return self.pos
def write(self, data):
data = self.compressor.compress(data)
self.pos += len(data)
self.fp.write(data)
def close(self):
data = self.compressor.flush()
self.pos += len(data)
self.fp.write(data)
def create_tar_bz2_from_files(fp, files, compresslevel=9):
"""Create a tar.bz2 file deterministically from files.
This is a glorified wrapper around ``create_tar_from_files`` that
adds bzip2 compression.
This function is similar to ``create_tar_gzip_from_files()``.
"""
proxy = _BZ2Proxy(fp, compresslevel=compresslevel)
create_tar_from_files(proxy, files)
proxy.close()

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

@ -0,0 +1,190 @@
# 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 hashlib
import os
import shutil
import stat
import tarfile
import tempfile
import unittest
from mozpack.archive import (
DEFAULT_MTIME,
create_tar_from_files,
create_tar_gz_from_files,
create_tar_bz2_from_files,
)
from mozunit import main
MODE_STANDARD = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
def file_hash(path):
h = hashlib.sha1()
with open(path, 'rb') as fh:
while True:
data = fh.read(8192)
if not data:
break
h.update(data)
return h.hexdigest()
class TestArchive(unittest.TestCase):
def _create_files(self, root):
files = {}
for i in range(10):
p = os.path.join(root, b'file%d' % i)
with open(p, 'wb') as fh:
fh.write(b'file%d' % i)
# Need to set permissions or umask may influence testing.
os.chmod(p, MODE_STANDARD)
files[b'file%d' % i] = p
return files
def _verify_basic_tarfile(self, tf):
self.assertEqual(len(tf.getmembers()), 10)
names = ['file%d' % i for i in range(10)]
self.assertEqual(tf.getnames(), names)
for ti in tf.getmembers():
self.assertEqual(ti.uid, 0)
self.assertEqual(ti.gid, 0)
self.assertEqual(ti.uname, '')
self.assertEqual(ti.gname, '')
self.assertEqual(ti.mode, MODE_STANDARD)
self.assertEqual(ti.mtime, DEFAULT_MTIME)
def test_dirs_refused(self):
d = tempfile.mkdtemp()
try:
tp = os.path.join(d, 'test.tar')
with open(tp, 'wb') as fh:
with self.assertRaisesRegexp(ValueError, 'not a regular'):
create_tar_from_files(fh, {'test': d})
finally:
shutil.rmtree(d)
def test_setuid_setgid_refused(self):
d = tempfile.mkdtemp()
try:
uid = os.path.join(d, 'setuid')
gid = os.path.join(d, 'setgid')
with open(uid, 'a'):
pass
with open(gid, 'a'):
pass
os.chmod(uid, MODE_STANDARD | stat.S_ISUID)
os.chmod(gid, MODE_STANDARD | stat.S_ISGID)
tp = os.path.join(d, 'test.tar')
with open(tp, 'wb') as fh:
with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
create_tar_from_files(fh, {'test': uid})
with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
create_tar_from_files(fh, {'test': gid})
finally:
shutil.rmtree(d)
def test_create_tar_basic(self):
d = tempfile.mkdtemp()
try:
files = self._create_files(d)
tp = os.path.join(d, 'test.tar')
with open(tp, 'wb') as fh:
create_tar_from_files(fh, files)
# Output should be deterministic.
self.assertEqual(file_hash(tp), 'cd16cee6f13391abd94dfa435d2633b61ed727f1')
with tarfile.open(tp, 'r') as tf:
self._verify_basic_tarfile(tf)
finally:
shutil.rmtree(d)
def test_executable_preserved(self):
d = tempfile.mkdtemp()
try:
p = os.path.join(d, 'exec')
with open(p, 'wb') as fh:
fh.write('#!/bin/bash\n')
os.chmod(p, MODE_STANDARD | stat.S_IXUSR)
tp = os.path.join(d, 'test.tar')
with open(tp, 'wb') as fh:
create_tar_from_files(fh, {'exec': p})
self.assertEqual(file_hash(tp), '357e1b81c0b6cfdfa5d2d118d420025c3c76ee93')
with tarfile.open(tp, 'r') as tf:
m = tf.getmember('exec')
self.assertEqual(m.mode, MODE_STANDARD | stat.S_IXUSR)
finally:
shutil.rmtree(d)
def test_create_tar_gz_basic(self):
d = tempfile.mkdtemp()
try:
files = self._create_files(d)
gp = os.path.join(d, 'test.tar.gz')
with open(gp, 'wb') as fh:
create_tar_gz_from_files(fh, files)
self.assertEqual(file_hash(gp), 'acb602239c1aeb625da5e69336775609516d60f5')
with tarfile.open(gp, 'r:gz') as tf:
self._verify_basic_tarfile(tf)
finally:
shutil.rmtree(d)
def test_tar_gz_name(self):
d = tempfile.mkdtemp()
try:
files = self._create_files(d)
gp = os.path.join(d, 'test.tar.gz')
with open(gp, 'wb') as fh:
create_tar_gz_from_files(fh, files, filename='foobar', compresslevel=1)
self.assertEqual(file_hash(gp), 'fd099f96480cc1100f37baa8e89a6b820dbbcbd3')
with tarfile.open(gp, 'r:gz') as tf:
self._verify_basic_tarfile(tf)
finally:
shutil.rmtree(d)
def test_create_tar_bz2_basic(self):
d = tempfile.mkdtemp()
try:
files = self._create_files(d)
bp = os.path.join(d, 'test.tar.bz2')
with open(bp, 'wb') as fh:
create_tar_bz2_from_files(fh, files)
self.assertEqual(file_hash(bp), '1827ad00dfe7acf857b7a1c95ce100361e3f6eea')
with tarfile.open(bp, 'r:bz2') as tf:
self._verify_basic_tarfile(tf)
finally:
shutil.rmtree(d)
if __name__ == '__main__':
main()

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

@ -23,16 +23,21 @@ task:
- 'index.gecko.v1.{{project}}.revision.linux.{{head_rev}}.{{build_name}}' - 'index.gecko.v1.{{project}}.revision.linux.{{head_rev}}.{{build_name}}'
- 'index.gecko.v1.{{project}}.latest.linux.{{build_name}}' - 'index.gecko.v1.{{project}}.latest.linux.{{build_name}}'
scopes: scopes:
# Nearly all of our build tasks use tc-vcs so just include the scope across - 'docker-worker:cache:level-{{level}}-hg-shared'
# the board. - 'docker-worker:cache:level-{{level}}-workspace'
- 'docker-worker:cache:level-{{level}}-{{project}}-tc-vcs'
payload: payload:
# Thirty minutes should be enough for lint checks # Thirty minutes should be enough for lint checks
maxRunTime: 1800 maxRunTime: 1800
cache: cache:
level-{{level}}-{{project}}-tc-vcs: '/home/worker/.tc-vcs' level-{{level}}-hg-shared: '/home/worker/hg-shared'
level-{{level}}-workspace: '/home/worker/workspace'
env:
GECKO_BASE_REPOSITORY: '{{base_repository}}'
GECKO_HEAD_REPOSITORY: '{{head_repository}}'
GECKO_HEAD_REV: '{{head_rev}}'
extra: extra:
build_product: '{{build_product}}' build_product: '{{build_product}}'

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

@ -20,11 +20,12 @@ task:
task-reference: "<docker-image>" task-reference: "<docker-image>"
command: command:
- /home/worker/bin/checkout-gecko-and-run
- /home/worker/workspace/gecko
- bash - bash
- -cx - -cx
- > - >
tc-vcs checkout ./gecko {{base_repository}} {{head_repository}} {{head_rev}} {{head_ref}} && cd /home/worker/workspace/gecko/tools/lint/eslint &&
cd gecko/tools/lint/eslint &&
/build/tooltool.py fetch -m manifest.tt && /build/tooltool.py fetch -m manifest.tt &&
tar xvfz eslint.tar.gz && tar xvfz eslint.tar.gz &&
rm eslint.tar.gz && rm eslint.tar.gz &&

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

@ -18,11 +18,12 @@ task:
taskId: taskId:
task-reference: "<docker-image>" task-reference: "<docker-image>"
command: command:
- /home/worker/bin/checkout-gecko-and-run
- /home/worker/workspace/gecko
- bash - bash
- -cx - -cx
- > - >
tc-vcs checkout ./gecko {{base_repository}} {{head_repository}} {{head_rev}} {{head_ref}} && cd /home/worker/workspace/gecko &&
cd gecko &&
./mach lint -l flake8 -f treeherder ./mach lint -l flake8 -f treeherder
extra: extra:
locations: locations:

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

@ -18,11 +18,12 @@ task:
taskId: taskId:
task-reference: "<docker-image>" task-reference: "<docker-image>"
command: command:
- /home/worker/bin/checkout-gecko-and-run
- /home/worker/workspace/gecko
- bash - bash
- -cx - -cx
- > - >
tc-vcs checkout ./gecko {{base_repository}} {{head_repository}} {{head_rev}} {{head_ref}} && cd /home/worker/workspace/gecko &&
cd gecko &&
./mach taskgraph python-tests ./mach taskgraph python-tests
extra: extra:
locations: locations:

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

@ -0,0 +1,42 @@
.. taskcluster_dockerimages:
=============
Docker Images
=============
TaskCluster Docker images are defined in the source directory under
``testing/docker``. Each directory therein contains the name of an
image used as part of the task graph.
Adding Extra Files to Images
============================
Dockerfile syntax has been extended to allow *any* file from the
source checkout to be added to the image build *context*. (Traditionally
you can only ``ADD`` files from the same directory as the Dockerfile.)
Simply add the following syntax as a comment in a Dockerfile::
# %include <path>
e.g.
# %include mach
# %include testing/mozharness
The argument to ``# %include`` is a relative path from the root level of
the source directory. It can be a file or a directory. If a file, only that
file will be added. If a directory, every file under that directory will be
added (even files that are untracked or ignored by version control).
Files added using ``# %include`` syntax are available inside the build
context under the ``topsrcdir/`` path.
Files are added as they exist on disk. e.g. executable flags should be
preserved. However, the file owner/group is changed to ``root`` and the
``mtime`` of the file is normalized.
Here is an example Dockerfile snippet::
# %include mach
ADD topsrcdir/mach /home/worker/mach

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

@ -28,3 +28,4 @@ check out the :doc:`how-to section <how-tos>`.
transforms transforms
yaml-templates yaml-templates
how-tos how-tos
docker-images

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

@ -27,13 +27,16 @@ routes:
payload: payload:
env: env:
GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-central' GECKO_BASE_REPOSITORY: 'https://hg.mozilla.org/mozilla-unified'
GECKO_HEAD_REPOSITORY: '{{{head_repository}}}' GECKO_HEAD_REPOSITORY: '{{{head_repository}}}'
GECKO_HEAD_REF: '{{head_ref}}' GECKO_HEAD_REF: '{{head_ref}}'
GECKO_HEAD_REV: '{{head_rev}}' GECKO_HEAD_REV: '{{head_rev}}'
ACTION_ARGS: >
--decision-id='{{decision_task_id}}'
--task-labels='{{task_labels}}'
cache: cache:
level-{{level}}-{{project}}-tc-vcs-public-sources: /home/worker/.tc-vcs/ level-{{level}}-hg-shared: /home/worker/hg-shared
level-{{level}}-{{project}}-gecko-decision: /home/worker/workspace level-{{level}}-{{project}}-gecko-decision: /home/worker/workspace
features: features:
@ -41,7 +44,7 @@ payload:
# Note: This task is built server side without the context or tooling that # Note: This task is built server side without the context or tooling that
# exist in tree so we must hard code the version # exist in tree so we must hard code the version
image: 'taskcluster/decision:0.1.0' image: 'taskcluster/decision:0.1.2'
# Virtually no network or other potentially risky operations happen as part # Virtually no network or other potentially risky operations happen as part
# of the task timeout aside from the initial clone. We intentionally have # of the task timeout aside from the initial clone. We intentionally have
@ -50,16 +53,7 @@ payload:
maxRunTime: 1800 maxRunTime: 1800
command: command:
- /bin/bash - /home/worker/bin/run-action
- -cx
- >
mkdir -p /home/worker/artifacts &&
checkout-gecko workspace &&
cd workspace/gecko &&
ln -s /home/worker/artifacts artifacts &&
./mach taskgraph action-task
--decision-id='{{decision_task_id}}'
--task-labels='{{task_labels}}'
artifacts: artifacts:
'public': 'public':

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

@ -21,7 +21,7 @@ ARTIFACT_URL = 'https://queue.taskcluster.net/v1/task/{}/artifacts/{}'
def load_image_by_name(image_name): def load_image_by_name(image_name):
context_path = os.path.join(GECKO, 'testing', 'docker', image_name) context_path = os.path.join(GECKO, 'testing', 'docker', image_name)
context_hash = docker.generate_context_hash(context_path) context_hash = docker.generate_context_hash(GECKO, context_path, image_name)
image_index_url = INDEX_URL.format('mozilla-central', image_name, context_hash) image_index_url = INDEX_URL.format('mozilla-central', image_name, context_hash)
print("Fetching", image_index_url) print("Fetching", image_index_url)

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

@ -9,13 +9,13 @@ import json
import os import os
import re import re
import urllib2 import urllib2
import tarfile
import time import time
from . import base from . import base
from taskgraph.util.docker import ( from taskgraph.util.docker import (
create_context_tar,
docker_image, docker_image,
generate_context_hash generate_context_hash,
) )
from taskgraph.util.templates import Templates from taskgraph.util.templates import Templates
@ -64,10 +64,8 @@ class DockerImageTask(base.Task):
templates = Templates(path) templates = Templates(path)
for image_name in config['images']: for image_name in config['images']:
context_path = os.path.join('testing', 'docker', image_name) context_path = os.path.join('testing', 'docker', image_name)
context_hash = generate_context_hash(context_path)
image_parameters = dict(parameters) image_parameters = dict(parameters)
image_parameters['context_hash'] = context_hash
image_parameters['context_path'] = context_path image_parameters['context_path'] = context_path
image_parameters['artifact_path'] = 'public/image.tar' image_parameters['artifact_path'] = 'public/image.tar'
image_parameters['image_name'] = image_name image_parameters['image_name'] = image_name
@ -80,12 +78,21 @@ class DockerImageTask(base.Task):
"artifacts/decision_task/image_contexts/{}/context.tar.gz".format(image_name)) "artifacts/decision_task/image_contexts/{}/context.tar.gz".format(image_name))
image_parameters['context_url'] = ARTIFACT_URL.format( image_parameters['context_url'] = ARTIFACT_URL.format(
os.environ['TASK_ID'], image_artifact_path) os.environ['TASK_ID'], image_artifact_path)
cls.create_context_tar(context_path, destination, image_name)
destination = os.path.abspath(destination)
if not os.path.exists(os.path.dirname(destination)):
os.makedirs(os.path.dirname(destination))
context_hash = create_context_tar(GECKO, context_path,
destination, image_name)
else: else:
# skip context generation since this isn't a decision task # skip context generation since this isn't a decision task
# TODO: generate context tarballs using subdirectory clones in # TODO: generate context tarballs using subdirectory clones in
# the image-building task so we don't have to worry about this. # the image-building task so we don't have to worry about this.
image_parameters['context_url'] = 'file:///tmp/' + image_artifact_path image_parameters['context_url'] = 'file:///tmp/' + image_artifact_path
context_hash = generate_context_hash(GECKO, context_path, image_name)
image_parameters['context_hash'] = context_hash
image_task = templates.load('image.yml', image_parameters) image_task = templates.load('image.yml', image_parameters)
@ -131,16 +138,6 @@ class DockerImageTask(base.Task):
return False, None return False, None
@classmethod
def create_context_tar(cls, context_dir, destination, image_name):
'Creates a tar file of a particular context directory.'
destination = os.path.abspath(destination)
if not os.path.exists(os.path.dirname(destination)):
os.makedirs(os.path.dirname(destination))
with tarfile.open(destination, 'w:gz') as tar:
tar.add(context_dir, arcname=image_name)
@classmethod @classmethod
def from_json(cls, task_dict): def from_json(cls, task_dict):
# Generating index_paths for optimization # Generating index_paths for optimization

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

@ -145,12 +145,13 @@ def set_interactive_task(task, interactive):
def remove_caches_from_task(task): def remove_caches_from_task(task):
r"""Remove all caches but tc-vcs from the task. r"""Remove all caches but vcs from the task.
:param task: task definition. :param task: task definition.
""" """
whitelist = [ whitelist = [
re.compile("^level-[123]-.*-tc-vcs(-public-sources)?$"), re.compile("^level-[123]-.*-tc-vcs(-public-sources)?$"),
re.compile("^level-[123]-hg-shared"),
re.compile("^tooltool-cache$"), re.compile("^tooltool-cache$"),
] ]
try: try:

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

@ -5,7 +5,6 @@
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
import unittest import unittest
import tempfile
import os import os
from ..task import docker_image from ..task import docker_image
@ -31,12 +30,6 @@ class TestDockerImageKind(unittest.TestCase):
# TODO: optimize_task # TODO: optimize_task
def test_create_context_tar(self):
image_dir = os.path.join(docker_image.GECKO, 'testing', 'docker', 'image_builder')
tarball = tempfile.mkstemp()[1]
self.task.create_context_tar(image_dir, tarball, 'image_builder')
self.failUnless(os.path.exists(tarball))
os.unlink(tarball)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

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

@ -6,6 +6,8 @@ from __future__ import absolute_import, print_function, unicode_literals
import os import os
import shutil import shutil
import stat
import tarfile
import tempfile import tempfile
import unittest import unittest
@ -13,6 +15,9 @@ from ..util import docker
from mozunit import MockedOpen from mozunit import MockedOpen
MODE_STANDARD = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
class TestDocker(unittest.TestCase): class TestDocker(unittest.TestCase):
def test_generate_context_hash(self): def test_generate_context_hash(self):
@ -26,8 +31,8 @@ class TestDocker(unittest.TestCase):
with open(os.path.join(tmpdir, 'docker', 'my-image', 'a-file'), "w") as f: with open(os.path.join(tmpdir, 'docker', 'my-image', 'a-file'), "w") as f:
f.write("data\n") f.write("data\n")
self.assertEqual( self.assertEqual(
docker.generate_context_hash('docker/my-image'), docker.generate_context_hash(docker.GECKO, 'docker/my-image', 'my-image'),
'781143fcc6cc72c9024b058665265cb6bae3fb8031cad7227dd169ffbfced434' '872d76a656f47ea17c043023ecc9ae6a222ba6d2a8df67b75498bba382e4fb07'
) )
finally: finally:
docker.GECKO = old_GECKO docker.GECKO = old_GECKO
@ -46,3 +51,138 @@ class TestDocker(unittest.TestCase):
files["{}/myimage/VERSION".format(docker.DOCKER_ROOT)] = "1.2.3" files["{}/myimage/VERSION".format(docker.DOCKER_ROOT)] = "1.2.3"
with MockedOpen(files): with MockedOpen(files):
self.assertEqual(docker.docker_image('myimage'), "mozilla/myimage:1.2.3") self.assertEqual(docker.docker_image('myimage'), "mozilla/myimage:1.2.3")
def test_create_context_tar_basic(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test_image')
os.mkdir(d)
with open(os.path.join(d, 'Dockerfile'), 'a'):
pass
os.chmod(os.path.join(d, 'Dockerfile'), MODE_STANDARD)
with open(os.path.join(d, 'extra'), 'a'):
pass
os.chmod(os.path.join(d, 'extra'), MODE_STANDARD)
tp = os.path.join(tmp, 'tar')
h = docker.create_context_tar(tmp, d, tp, 'my_image')
self.assertEqual(h, '2a6d7f1627eba60daf85402418e041d728827d309143c6bc1c6bb3035bde6717')
# File prefix should be "my_image"
with tarfile.open(tp, 'r:gz') as tf:
self.assertEqual(tf.getnames(), [
'my_image/Dockerfile',
'my_image/extra',
])
finally:
shutil.rmtree(tmp)
def test_create_context_topsrcdir_files(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test-image')
os.mkdir(d)
with open(os.path.join(d, 'Dockerfile'), 'wb') as fh:
fh.write(b'# %include extra/file0\n')
os.chmod(os.path.join(d, 'Dockerfile'), MODE_STANDARD)
extra = os.path.join(tmp, 'extra')
os.mkdir(extra)
with open(os.path.join(extra, 'file0'), 'a'):
pass
os.chmod(os.path.join(extra, 'file0'), MODE_STANDARD)
tp = os.path.join(tmp, 'tar')
h = docker.create_context_tar(tmp, d, tp, 'test_image')
self.assertEqual(h, '20faeb7c134f21187b142b5fadba94ae58865dc929c6c293d8cbc0a087269338')
with tarfile.open(tp, 'r:gz') as tf:
self.assertEqual(tf.getnames(), [
'test_image/Dockerfile',
'test_image/topsrcdir/extra/file0',
])
finally:
shutil.rmtree(tmp)
def test_create_context_absolute_path(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test-image')
os.mkdir(d)
# Absolute paths in %include syntax are not allowed.
with open(os.path.join(d, 'Dockerfile'), 'wb') as fh:
fh.write(b'# %include /etc/shadow\n')
with self.assertRaisesRegexp(Exception, 'cannot be absolute'):
docker.create_context_tar(tmp, d, os.path.join(tmp, 'tar'), 'test')
finally:
shutil.rmtree(tmp)
def test_create_context_outside_topsrcdir(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test-image')
os.mkdir(d)
with open(os.path.join(d, 'Dockerfile'), 'wb') as fh:
fh.write(b'# %include foo/../../../etc/shadow\n')
with self.assertRaisesRegexp(Exception, 'path outside topsrcdir'):
docker.create_context_tar(tmp, d, os.path.join(tmp, 'tar'), 'test')
finally:
shutil.rmtree(tmp)
def test_create_context_missing_extra(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test-image')
os.mkdir(d)
with open(os.path.join(d, 'Dockerfile'), 'wb') as fh:
fh.write(b'# %include does/not/exist\n')
with self.assertRaisesRegexp(Exception, 'path does not exist'):
docker.create_context_tar(tmp, d, os.path.join(tmp, 'tar'), 'test')
finally:
shutil.rmtree(tmp)
def test_create_context_extra_directory(self):
tmp = tempfile.mkdtemp()
try:
d = os.path.join(tmp, 'test-image')
os.mkdir(d)
with open(os.path.join(d, 'Dockerfile'), 'wb') as fh:
fh.write(b'# %include extra\n')
fh.write(b'# %include file0\n')
os.chmod(os.path.join(d, 'Dockerfile'), MODE_STANDARD)
extra = os.path.join(tmp, 'extra')
os.mkdir(extra)
for i in range(3):
p = os.path.join(extra, 'file%d' % i)
with open(p, 'wb') as fh:
fh.write(b'file%d' % i)
os.chmod(p, MODE_STANDARD)
with open(os.path.join(tmp, 'file0'), 'a'):
pass
os.chmod(os.path.join(tmp, 'file0'), MODE_STANDARD)
tp = os.path.join(tmp, 'tar')
h = docker.create_context_tar(tmp, d, tp, 'my_image')
self.assertEqual(h, 'e5440513ab46ae4c1d056269e1c6715d5da7d4bd673719d360411e35e5b87205')
with tarfile.open(tp, 'r:gz') as tf:
self.assertEqual(tf.getnames(), [
'my_image/Dockerfile',
'my_image/topsrcdir/extra/file0',
'my_image/topsrcdir/extra/file1',
'my_image/topsrcdir/extra/file2',
'my_image/topsrcdir/file0',
])
finally:
shutil.rmtree(tmp)

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

@ -6,6 +6,12 @@ from __future__ import absolute_import, print_function, unicode_literals
import hashlib import hashlib
import os import os
import tempfile
from mozpack.archive import (
create_tar_gz_from_files,
)
GECKO = os.path.realpath(os.path.join(__file__, '..', '..', '..', '..')) GECKO = os.path.realpath(os.path.join(__file__, '..', '..', '..', '..'))
DOCKER_ROOT = os.path.join(GECKO, 'testing', 'docker') DOCKER_ROOT = os.path.join(GECKO, 'testing', 'docker')
@ -28,28 +34,83 @@ def docker_image(name):
return '{}/{}:{}'.format(registry, name, version) return '{}/{}:{}'.format(registry, name, version)
def generate_context_hash(image_path): def generate_context_hash(topsrcdir, image_path, image_name):
'''Generates a sha256 hash for context directory used to build an image. """Generates a sha256 hash for context directory used to build an image."""
Contents of the directory are sorted alphabetically, contents of each file is hashed, # It is a bit unfortunate we have to create a temp file here - it would
and then a hash is created for both the file hashs as well as their paths. # be nicer to use an in-memory buffer.
fd, p = tempfile.mkstemp()
os.close(fd)
try:
return create_context_tar(topsrcdir, image_path, p, image_name)
finally:
os.unlink(p)
This ensures that hashs are consistent and also change based on if file locations
within the context directory change.
'''
context_hash = hashlib.sha256()
files = []
for dirpath, dirnames, filenames in os.walk(os.path.join(GECKO, image_path)): def create_context_tar(topsrcdir, context_dir, out_path, prefix):
for filename in filenames: """Create a context tarball.
files.append(os.path.join(dirpath, filename))
for filename in sorted(files): A directory ``context_dir`` containing a Dockerfile will be assembled into
relative_filename = filename.replace(GECKO, '') a gzipped tar file at ``out_path``. Files inside the archive will be
with open(filename, 'rb') as f: prefixed by directory ``prefix``.
file_hash = hashlib.sha256()
data = f.read()
file_hash.update(data)
context_hash.update(file_hash.hexdigest() + '\t' + relative_filename + '\n')
return context_hash.hexdigest() We also scan the source Dockerfile for special syntax that influences
context generation.
If a line in the Dockerfile has the form ``# %include <path>``,
the relative path specified on that line will be matched against
files in the source repository and added to the context under the
path ``topsrcdir/``. If an entry is a directory, we add all files
under that directory.
Returns the SHA-256 hex digest of the created archive.
"""
archive_files = {}
for root, dirs, files in os.walk(context_dir):
for f in files:
source_path = os.path.join(root, f)
rel = source_path[len(context_dir) + 1:]
archive_path = os.path.join(prefix, rel)
archive_files[archive_path] = source_path
# Parse Dockerfile for special syntax of extra files to include.
with open(os.path.join(context_dir, 'Dockerfile'), 'rb') as fh:
for line in fh:
line = line.rstrip()
if not line.startswith('# %include'):
continue
p = line[len('# %include '):].strip()
if os.path.isabs(p):
raise Exception('extra include path cannot be absolute: %s' % p)
fs_path = os.path.normpath(os.path.join(topsrcdir, p))
# Check for filesystem traversal exploits.
if not fs_path.startswith(topsrcdir):
raise Exception('extra include path outside topsrcdir: %s' % p)
if not os.path.exists(fs_path):
raise Exception('extra include path does not exist: %s' % p)
if os.path.isdir(fs_path):
for root, dirs, files in os.walk(fs_path):
for f in files:
source_path = os.path.join(root, f)
archive_path = os.path.join(prefix, 'topsrcdir', p, f)
archive_files[archive_path] = source_path
else:
archive_path = os.path.join(prefix, 'topsrcdir', p)
archive_files[archive_path] = fs_path
with open(out_path, 'wb') as fh:
create_tar_gz_from_files(fh, archive_files, '%s.tar.gz' % prefix)
h = hashlib.sha256()
with open(out_path, 'rb') as fh:
while True:
data = fh.read(32768)
if not data:
break
h.update(data)
return h.hexdigest()

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

@ -1,14 +1,16 @@
FROM ubuntu:14.04 FROM ubuntu:16.04
MAINTAINER Greg Arndt <garndt@mozilla.com> MAINTAINER Greg Arndt <garndt@mozilla.com>
# install non-build specific dependencies in a single layer # Add worker user
ADD system-setup.sh /tmp/system-setup.sh RUN useradd -d /home/worker -s /bin/bash -m worker
RUN mkdir /home/worker/artifacts && chown worker:worker /home/worker/artifacts
ADD system-setup.sh tooltool.py /tmp/
RUN bash /tmp/system-setup.sh RUN bash /tmp/system-setup.sh
ADD bin /home/worker/bin ADD bin /home/worker/bin
RUN chmod +x /home/worker/bin/*
ENV PATH /home/worker/bin:/usr/local/lib/python2.7.10/bin:$PATH ENV PATH /home/worker/bin:$PATH
ENV SHELL /bin/bash ENV SHELL /bin/bash
ENV HOME /home/worker ENV HOME /home/worker

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

@ -1 +1 @@
0.1.0 0.1.2

30
testing/docker/decision/bin/checkout-gecko Normal file → Executable file
Просмотреть файл

@ -1,13 +1,11 @@
#! /bin/bash -e #! /bin/bash -e
set -e set -ex
# Ensure we have at least enough to check gecko out... # Ensure we have at least enough to check gecko out...
test $GECKO_BASE_REPOSITORY test $GECKO_BASE_REPOSITORY
# Workspace to checkout gecko into... DESTDIR=$1
WORKSPACE=$1
mkdir -p $WORKSPACE
res=`curl --fail --retry 5 http://taskcluster/secrets/v1/secret/project/taskcluster/gecko/hgfingerprint` res=`curl --fail --retry 5 http://taskcluster/secrets/v1/secret/project/taskcluster/gecko/hgfingerprint`
FP=`echo $res | jq -r .secret.content` FP=`echo $res | jq -r .secret.content`
@ -18,16 +16,16 @@ if [[ ! "$FP" =~ ^[a-f0-9:]+$ ]]; then
exit 1 exit 1
fi fi
mkdir /etc/mercurial if [ -n "${GECKO_HEAD_REV}" ]; then
cat >/etc/mercurial/hgrc <<EOF args="--revision ${GECKO_HEAD_REV}"
[hostfingerprints] else
hg.mozilla.org = $FP args="--branch ${GECKO_HEAD_REF}"
EOF fi
# Note that tc-vcs requires only the first two arguments so others are optional. hg --config hostfingerprints.hg.mozilla.org=${FP} robustcheckout \
# This is intended to make it easier to clone local directories. --sharebase /home/worker/hg-shared \
tc-vcs checkout $WORKSPACE/gecko \ --purge \
$GECKO_BASE_REPOSITORY \ ${args} \
$GECKO_HEAD_REPOSITORY \ --upstream ${GECKO_BASE_REPOSITORY} \
$GECKO_HEAD_REV \ ${GECKO_HEAD_REPOSITORY} \
$GECKO_HEAD_REF ${DESTDIR}

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

@ -0,0 +1,19 @@
#!/bin/bash
# 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/.
set -ex
# The script starts executing as root. We need to change ownership
# of the caches because they are initially owned by root:root.
if [ $(id -u) = 0 ]; then
chown worker:worker /home/worker/hg-shared /home/worker/workspace
exec sudo -E -u worker /home/worker/bin/run-action "${@}"
fi
/home/worker/bin/checkout-gecko /home/worker/workspace/gecko
cd /home/worker/workspace/gecko
ln -s /home/worker/artifacts artifacts &&
eval "./mach taskgraph action-task ${ACTION_ARGS}"

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

@ -0,0 +1,19 @@
#!/bin/bash
# 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/.
set -ex
# The script starts executing as root. We need to change ownership
# of the caches because they are initially owned by root:root.
if [ $(id -u) = 0 ]; then
chown worker:worker /home/worker/hg-shared /home/worker/workspace
exec sudo -E -u worker /home/worker/bin/run-decision "${@}"
fi
/home/worker/bin/checkout-gecko /home/worker/workspace/gecko
cd /home/worker/workspace/gecko
ln -s /home/worker/artifacts artifacts
eval "./mach taskgraph decision ${DECISION_ARGS}"

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

@ -6,148 +6,75 @@ test `whoami` == 'root'
apt-get update apt-get update
apt-get install -y --force-yes --no-install-recommends \ apt-get install -y --force-yes --no-install-recommends \
autotools-dev \
blt-dev \
bzip2 \
curl \
ca-certificates \ ca-certificates \
dpkg-dev \ curl \
gcc-multilib \
g++-multilib \
jq \ jq \
libbluetooth-dev \ python \
libbz2-dev \ sudo
libexpat1-dev \
libffi-dev \
libffi6 \
libffi6-dbg \
libgdbm-dev \
libgpm2 \
libncursesw5-dev \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
libtinfo-dev \
make \
mime-support \
netbase \
net-tools \
python-dev \
python-pip \
python-crypto \
python-mox3 \
python-pil \
python-ply \
quilt \
tar \
tk-dev \
xz-utils \
zlib1g-dev
BUILD=/root/build BUILD=/root/build
mkdir $BUILD mkdir $BUILD
tooltool_fetch() { tooltool_fetch() {
cat >manifest.tt cat >manifest.tt
python $BUILD/tooltool.py fetch python2.7 /tmp/tooltool.py fetch
rm manifest.tt rm manifest.tt
} }
curl https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py > ${BUILD}/tooltool.py # Install Mercurial from custom debs since distro packages tend to lag behind.
cd $BUILD cd $BUILD
tooltool_fetch <<'EOF' tooltool_fetch <<EOF
[ [
{ {
"size": 12250696, "size": 44878,
"digest": "67615a6defbcda062f15a09f9dd3b9441afd01a8cc3255e5bc45b925378a0ddc38d468b7701176f6cc153ec52a4f21671b433780d9bde343aa9b9c1b2ae29feb", "digest": "7b1fc1217e0dcaeea852b0af2dc559b1aafb704fbee7e29cbec75af57bacb84910a7ec92b5c33f04ee98f23b3a57f1fa451173fe7c8a96f58faefe319dc7dde1",
"algorithm": "sha512", "algorithm": "sha512",
"filename": "Python-2.7.10.tar.xz", "filename": "mercurial_3.8.4_amd64.deb"
"unpack": true
}
]
EOF
cd Python-2.7.10
./configure --prefix /usr/local/lib/python2.7.10
make -j$(nproc)
make install
PATH=/usr/local/lib/python2.7.10/bin/:$PATH
python --version
# Enough python utilities to get "peep" working
cd $BUILD
tooltool_fetch <<'EOF'
[
{
"size": 630700,
"digest": "1367f3a10c1fef2f8061e430585f1927f6bd7c416e764d65cea1f4255824d549efa77beef8ff784bbd62c307b4b1123502e7b3fd01a243c0cc5b433a841cc8b5",
"algorithm": "sha512",
"filename": "setuptools-18.1.tar.gz",
"unpack": true
}, },
{ {
"size": 1051205, "size": 1818422,
"digest": "e7d2e003ec60fce5a75a6a23711d7f9b155e898faebcf55f3abdd912ef513f4e0cf43daca8f9da7179a7a4efe6e4a625a532d051349818847df1364eb5b326de", "digest": "b476e2612e7495a1c7c5adfd84511aa7479e26cc9070289513ec705fbfc4c61806ce2dbcceca0e63f2e80669be416f3467a3cebb522dcb8a6aeb62cdd3df82f2",
"algorithm": "sha512", "algorithm": "sha512",
"filename": "pip-6.1.1.tar.gz", "filename": "mercurial-common_3.8.4_all.deb"
"unpack": true
},
{
"size": 26912,
"digest": "9d730ed7852d4d217aaddda959cd5f871ef1b26dd6c513a3780bbb04a5a93a49d6b78e95c2274451a1311c10cc0a72755b269dc9af62640474e6e73a1abec370",
"algorithm": "sha512",
"filename": "peep-2.4.1.tar.gz",
"unpack": false
} }
] ]
EOF EOF
cd $BUILD dpkg -i mercurial-common_3.8.4_all.deb mercurial_3.8.4_amd64.deb
cd setuptools-18.1
python setup.py install
# NOTE: latest peep is not compatible with pip>=7.0
# https://github.com/erikrose/peep/pull/94
cd $BUILD mkdir -p /usr/local/mercurial
cd pip-6.1.1 chown 755 /usr/local/mercurial
python setup.py install cd /usr/local/mercurial
cd $BUILD
pip install peep-2.4.1.tar.gz
# Peep (latest)
cd $BUILD
pip install peep
# remaining Python utilities are installed with `peep` from upstream
# repositories; peep verifies file integrity for us
cat >requirements.txt <<'EOF'
# sha256: 90pZQ6kAXB6Je8-H9-ivfgDAb6l3e5rWkfafn6VKh9g
virtualenv==13.1.2
# sha256: wJnELXTi1SC2HdNyzZlrD6dgXAZheDT9exPHm5qaWzA
mercurial==3.7.3
EOF
peep install -r requirements.txt
# Install node
tooltool_fetch <<'EOF' tooltool_fetch <<'EOF'
[ [
{ {
"size": 5676610, "size": 11849,
"digest": "ce27b788dfd141a5ba7674332825fc136fe2c4f49a319dd19b3a87c8fffa7a97d86cbb8535661c9a68c9122719aa969fc6a8c886458a0df9fc822eec99ed130b", "digest": "c88d9b8afd6649bd28bbacfa654ebefec8087a01d1662004aae088d485edeb03a92df1193d1310c0369d7721f475b974fcd4a911428ec65936f7e40cf1609c49",
"algorithm": "sha512", "algorithm": "sha512",
"filename": "node-v0.10.36-linux-x64.tar.gz" "filename": "robustcheckout.py"
} }
] ]
EOF EOF
tar -C /usr/local -xz --strip-components 1 < node-*.tar.gz
node -v # verify
npm install -g taskcluster-vcs@2.3.34 chmod 644 /usr/local/mercurial/robustcheckout.py
# Install a global hgrc file with reasonable defaults.
mkdir -p /etc/mercurial
cat >/etc/mercurial/hgrc <<EOF
# By default the progress bar starts after 3s and updates every 0.1s. We
# change this so it shows and updates every 1.0s.
[progress]
delay = 1.0
refresh = 1.0
[web]
cacerts = /etc/ssl/certs/ca-certificates.crt
[extensions]
robustcheckout = /usr/local/mercurial/robustcheckout.py
EOF
chmod 644 /etc/mercurial/hgrc
cd / cd /
rm -rf $BUILD rm -rf $BUILD

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

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

@ -4,15 +4,19 @@ MAINTAINER Andrew Halberstadt <ahalberstadt@mozilla.com>
RUN useradd -d /home/worker -s /bin/bash -m worker RUN useradd -d /home/worker -s /bin/bash -m worker
WORKDIR /home/worker WORKDIR /home/worker
# Install tooltool directly from github.
RUN mkdir /build RUN mkdir /build
ADD https://raw.githubusercontent.com/mozilla/build-tooltool/master/tooltool.py /build/tooltool.py # %include testing/docker/decision/tooltool.py
RUN chmod +rx /build/tooltool.py ADD topsrcdir/testing/docker/decision/tooltool.py /build/tooltool.py
# Install lint packages # %include testing/docker/recipes/install-mercurial.sh
ADD topsrcdir/testing/docker/recipes/install-mercurial.sh /build/install-mercurial.sh
ADD system-setup.sh /tmp/system-setup.sh ADD system-setup.sh /tmp/system-setup.sh
RUN bash /tmp/system-setup.sh RUN bash /tmp/system-setup.sh
# %include testing/docker/recipes/checkout-gecko-and-run
ADD topsrcdir/testing/docker/recipes/checkout-gecko-and-run /home/worker/bin/checkout-gecko-and-run
RUN chown -R worker:worker /home/worker/bin && chmod 755 /home/worker/bin/*
# Set variable normally configured at login, by the shells parent process, these # Set variable normally configured at login, by the shells parent process, these
# are taken from GNU su manual # are taken from GNU su manual
ENV HOME /home/worker ENV HOME /home/worker

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

@ -11,7 +11,6 @@ cd /setup
apt_packages=() apt_packages=()
apt_packages+=('curl') apt_packages+=('curl')
apt_packages+=('mercurial')
apt_packages+=('python') apt_packages+=('python')
apt_packages+=('python-pip') apt_packages+=('python-pip')
apt_packages+=('sudo') apt_packages+=('sudo')
@ -31,6 +30,8 @@ tooltool_fetch() {
rm manifest.tt rm manifest.tt
} }
cd /build
. install-mercurial.sh
### ###
# ESLint Setup # ESLint Setup
@ -40,6 +41,7 @@ tooltool_fetch() {
# For future reference things like this don't need to be uploaded to tooltool, as long # For future reference things like this don't need to be uploaded to tooltool, as long
# as we verify the hash, we can download it from the external net. # as we verify the hash, we can download it from the external net.
cd /setup
tooltool_fetch <<'EOF' tooltool_fetch <<'EOF'
[ [
{ {
@ -54,33 +56,24 @@ tar -C /usr/local --strip-components 1 -xJ < node-*.tar.xz
node -v # verify node -v # verify
npm -v npm -v
# install taskcluster-vcs@2.3.12
tooltool_fetch <<'EOF'
[
{
"size": 6282161,
"visibility": "public",
"digest": "a781a96e596f6403eca6ec2300adb9c1a396659393e16993c66f98a658050e557bc681d521f70b50c1162aa4b435274e0098ffcbd37cbe969c0e4f69be19a1e0",
"algorithm": "sha512",
"filename": "taskcluster-vcs-v2.3.12.tar.gz"
}
]
EOF
npm install -g taskcluster-vcs-v2.3.12.tar.gz
### ###
# Flake8 Setup # Flake8 Setup
### ###
cd /setup
cat >requirements.txt <<'EOF' cat >requirements.txt <<'EOF'
mccabe==0.4.0 --hash=sha256:cbc2938f6c01061bc6d21d0c838c2489664755cb18676f0734d7617f4577d09e flake8==2.5.4 \
pep8==1.7.0 --hash=sha256:4fc2e478addcf17016657dff30b2d8d611e8341fac19ccf2768802f6635d7b8a --hash=sha256:fb5a67af4024622287a76abf6b7fe4fb3cfacf765a790976ce64f52c44c88e4a
pyflakes==1.2.3 --hash=sha256:e87bac26c62ea5b45067cc89e4a12f56e1483f1f2cda17e7c9b375b9fd2f40da mccabe==0.4.0 \
flake8==2.5.4 --hash=sha256:fb5a67af4024622287a76abf6b7fe4fb3cfacf765a790976ce64f52c44c88e4a --hash=sha256:cbc2938f6c01061bc6d21d0c838c2489664755cb18676f0734d7617f4577d09e
pep8==1.7.0 \
--hash=sha256:4fc2e478addcf17016657dff30b2d8d611e8341fac19ccf2768802f6635d7b8a
pyflakes==1.2.3 \
--hash=sha256:e87bac26c62ea5b45067cc89e4a12f56e1483f1f2cda17e7c9b375b9fd2f40da
EOF EOF
pip install --require-hashes -r requirements.txt pip install --require-hashes -r requirements.txt
cd / cd /
rm -rf /setup rm -rf /setup

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

@ -0,0 +1,37 @@
#!/bin/bash
# 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/.
set -ex
# The script starts executing as root. We need to change ownership
# of the caches because they are initially owned by root:root. There
# may not be a cache mount/directory on some instances. So create the
# directory if missing.
if [ $(id -u) = 0 ]; then
mkdir -p /home/worker/workspace
chown worker:worker /home/worker/hg-shared /home/worker/workspace
exec sudo -E -u worker ${0} "${@}"
fi
DEST=$1
shift
# We set the base repository to mozilla-central so tc-vcs doesn't get
# confused. Switch to mozilla-unified because robustcheckout works best
# with it.
if [ "${GECKO_BASE_REPOSITORY}" = "https://hg.mozilla.org/mozilla-central" ]; then
GECKO_BASE_REPOSITORY=https://hg.mozilla.org/mozilla-unified
fi
/usr/bin/hg robustcheckout \
--sharebase /home/worker/hg-shared \
--purge \
--upstream ${GECKO_BASE_REPOSITORY} \
--revision ${GECKO_HEAD_REV} \
${GECKO_HEAD_REPOSITORY} \
${DEST}
exec "${@}"

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

@ -0,0 +1,59 @@
#!/bin/bash
# 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/.
# This script installs and configures Mercurial.
set -e
# ASSERTION: We are running Ubuntu 16.04.
tooltool_fetch <<EOF
[
{
"size": 44878,
"digest": "7b1fc1217e0dcaeea852b0af2dc559b1aafb704fbee7e29cbec75af57bacb84910a7ec92b5c33f04ee98f23b3a57f1fa451173fe7c8a96f58faefe319dc7dde1",
"algorithm": "sha512",
"filename": "mercurial_3.8.4_amd64.deb"
},
{
"size": 1818422,
"digest": "b476e2612e7495a1c7c5adfd84511aa7479e26cc9070289513ec705fbfc4c61806ce2dbcceca0e63f2e80669be416f3467a3cebb522dcb8a6aeb62cdd3df82f2",
"algorithm": "sha512",
"filename": "mercurial-common_3.8.4_all.deb"
}
]
EOF
dpkg -i mercurial-common_3.8.4_all.deb mercurial_3.8.4_amd64.deb
mkdir -p /usr/local/mercurial
cd /usr/local/mercurial
tooltool_fetch <<'EOF'
[
{
"size": 11849,
"digest": "c88d9b8afd6649bd28bbacfa654ebefec8087a01d1662004aae088d485edeb03a92df1193d1310c0369d7721f475b974fcd4a911428ec65936f7e40cf1609c49",
"algorithm": "sha512",
"filename": "robustcheckout.py"
}
]
EOF
chmod 644 /usr/local/mercurial/robustcheckout.py
mkdir -p /etc/mercurial
cat >/etc/mercurial/hgrc <<EOF
# By default the progress bar starts after 3s and updates every 0.1s. We
# change this so it shows and updates every 1.0s.
[progress]
delay = 1.0
refresh = 1.0
[web]
cacerts = /etc/ssl/certs/ca-certificates.crt
[extensions]
robustcheckout = /usr/local/mercurial/robustcheckout.py
EOF
chmod 644 /etc/mercurial/hgrc

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

@ -62,18 +62,11 @@ class MarionetteHarness(object):
self._testcase_class.pydebugger = __import__(self.args['pydebugger']) self._testcase_class.pydebugger = __import__(self.args['pydebugger'])
def run(self): def run(self):
try:
self.process_args() self.process_args()
tests = self.args.pop('tests') tests = self.args.pop('tests')
runner = self._runner_class(**self.args) runner = self._runner_class(**self.args)
runner.run_tests(tests) runner.run_tests(tests)
return runner.failed + runner.crashed return runner.failed + runner.crashed
except Exception:
logger = self.args.get('logger')
if logger:
logger.error('Failure during test execution.',
exc_info=True)
raise
def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments, def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
@ -88,11 +81,13 @@ def cli(runner_class=MarionetteTestRunner, parser_class=MarionetteArguments,
""" """
logger = mozlog.commandline.setup_logging('Marionette test runner', {}) logger = mozlog.commandline.setup_logging('Marionette test runner', {})
try: try:
failed = harness_class(runner_class, parser_class, testcase_class, args=args).run() harness_instance = harness_class(runner_class, parser_class, testcase_class,
args=args)
failed = harness_instance.run()
if failed > 0: if failed > 0:
sys.exit(10) sys.exit(10)
except Exception: except Exception:
logger.error('Failure during harness setup', exc_info=True) logger.error('Failure during harness execution', exc_info=True)
sys.exit(1) sys.exit(1)
sys.exit(0) sys.exit(0)

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

@ -132,7 +132,6 @@ skip-if = true # Bug 1265878
[../tests/dom/media/tests/mochitest/test_peerConnection_verifyVideoAfterRenegotiation.html] [../tests/dom/media/tests/mochitest/test_peerConnection_verifyVideoAfterRenegotiation.html]
[../tests/dom/media/tests/mochitest/test_peerConnection_webAudio.html] [../tests/dom/media/tests/mochitest/test_peerConnection_webAudio.html]
[../tests/dom/media/tests/mochitest/test_selftest.html] [../tests/dom/media/tests/mochitest/test_selftest.html]
[../tests/dom/media/tests/mochitest/test_zmedia_cleanup.html]
[../tests/dom/media/tests/mochitest/identity/test_fingerprints.html] [../tests/dom/media/tests/mochitest/identity/test_fingerprints.html]
skip-if = true # Bug 1200411 skip-if = true # Bug 1200411
[../tests/dom/media/tests/mochitest/identity/test_getIdentityAssertion.html] [../tests/dom/media/tests/mochitest/identity/test_getIdentityAssertion.html]

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

@ -1,8 +0,0 @@
config = {
'base_name': 'Android armv7 API 11+ %(branch)s',
'stage_platform': 'android-api-11',
'build_type': 'api-11-opt',
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-11/nightly',
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
'multi_locale_config_platform': 'android',
}

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

@ -1,9 +0,0 @@
config = {
'base_name': 'Android armv7 API 11+ %(branch)s debug',
'stage_platform': 'android-api-11-debug',
'build_type': 'api-11-debug',
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-11/debug',
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
'multi_locale_config_platform': 'android',
'debug_build': True,
}

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

@ -1,8 +0,0 @@
config = {
'base_name': 'Android armv7 API 9 %(branch)s',
'stage_platform': 'android-api-9',
'build_type': 'api-9-opt',
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-9-10-constrained/nightly',
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
'multi_locale_config_platform': 'android',
}

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

@ -1,9 +0,0 @@
config = {
'base_name': 'Android armv7 API 9 %(branch)s debug',
'stage_platform': 'android-api-9-debug',
'build_type': 'api-9-debug',
'src_mozconfig': 'mobile/android/config/mozconfigs/android-api-9-10-constrained/debug',
'tooltool_manifest_src': 'mobile/android/config/tooltool-manifests/android/releng.manifest',
'multi_locale_config_platform': 'android',
'debug_build': True,
}

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