merge mozilla-inbound to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2013-11-11 08:50:14 +01:00
Родитель 1b73d5648b 4ae5a9d8a2
Коммит 37ac775340
247 изменённых файлов: 4166 добавлений и 4436 удалений

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

@ -5,6 +5,7 @@
#include "FocusManager.h"
#include "Accessible-inl.h"
#include "AccIterator.h"
#include "DocAccessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
@ -288,8 +289,30 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
// Fire menu start/end events for ARIA menus.
if (target->ARIARole() == roles::MENUITEM) {
// The focus was moved into menu.
Accessible* ARIAMenubar =
nsAccUtils::GetAncestorWithRole(target, roles::MENUBAR);
Accessible* ARIAMenubar = nullptr;
Accessible* child = target;
Accessible* parent = child->Parent();
while (parent) {
nsRoleMapEntry* roleMap = parent->ARIARoleMap();
if (roleMap) {
if (roleMap->Is(nsGkAtoms::menubar)) {
ARIAMenubar = parent;
break;
}
// Go up in the parent chain of the menu hierarchy.
if (roleMap->Is(nsGkAtoms::menuitem) || roleMap->Is(nsGkAtoms::menu)) {
child = parent;
parent = child->Parent();
continue;
}
}
// If no required context role then check aria-owns relation.
RelatedAccIterator iter(child->Document(), child->GetContent(),
nsGkAtoms::aria_owns);
parent = iter.Next();
}
if (ARIAMenubar != mActiveARIAMenubar) {
// Leaving ARIA menu. Fire menu_end event on current menubar.

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

@ -210,22 +210,6 @@ nsAccUtils::GetARIAToken(dom::Element* aElement, nsIAtom* aAttr)
return nullptr;
}
Accessible*
nsAccUtils::GetAncestorWithRole(Accessible* aDescendant, uint32_t aRole)
{
Accessible* document = aDescendant->Document();
Accessible* parent = aDescendant;
while ((parent = parent->Parent())) {
uint32_t testRole = parent->Role();
if (testRole == aRole)
return parent;
if (parent == document)
break;
}
return nullptr;
}
Accessible*
nsAccUtils::GetSelectableContainer(Accessible* aAccessible, uint64_t aState)
{

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

@ -116,17 +116,6 @@ public:
return GetAccService()->GetDocAccessible(docShell->GetPresShell());
}
/**
* Return ancestor in this document with the given role if it exists.
*
* @param aDescendant [in] descendant to start search with
* @param aRole [in] role to find matching ancestor for
* @return the ancestor accessible with the given role, or
* nullptr if no match is found
*/
static Accessible* GetAncestorWithRole(Accessible* aDescendant,
uint32_t aRole);
/**
* Return single or multi selectable container for the given item.
*

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

@ -165,6 +165,10 @@
gQueue.push(new focusInsideMenu("menu-edit", "menubar"));
gQueue.push(new blurMenu("menubar"));
gQueue.push(new focusMenu("menubar3", "mb3-mi-outside"));
gQueue.push(new showMenu("mb4-menu", document, kViaDisplayStyle));
gQueue.push(new focusMenu("menubar4", "mb4-item1"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -178,22 +182,27 @@
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=606207"
title="Dojo dropdown buttons are broken">
Mozilla Bug 606207
Bug 606207
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=614829"
title="Menupopup end event isn't fired for ARIA menus">
Mozilla Bug 614829
Bug 614829
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=615189"
title="Clean up FireAccessibleFocusEvent">
Mozilla Bug 615189
Bug 615189
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=673958"
title="Rework accessible focus handling">
Mozilla Bug 673958
Bug 673958
</a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=933322"
title="menustart/end events are missing when aria-owns makes a menu hierarchy">
Bug 933322
</a>
<p id="display"></p>
@ -227,6 +236,18 @@
</div>
<div tabindex="0" id="outsidemenu">outsidemenu</div>
<!-- aria-owns relations -->
<div id="menubar3" role="menubar" aria-owns="mb3-mi-outside"></div>
<div id="mb3-mi-outside" role="menuitem" tabindex="0">Outside</div>
<div id="menubar4" role="menubar">
<div role="menuitem" aria-haspopup="true" aria-owns="mb4-menu">Item</div>
</div>
<div id="mb4-menu" role="menu" style="display:none;">
<div role="menuitem" id="mb4-item1" tabindex="0">Item 1.1</div>
<div role="menuitem" tabindex="0">Item 1.2</div>
</div>
<div id="eventdump"></div>
</body>

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

@ -52,7 +52,7 @@ endif
ifdef MOZ_PKG_MANIFEST_P
$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) FORCE
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@)
ifdef MOZ_CHROME_MULTILOCALE
printf "\n[multilocale]\n" >> $@
for LOCALE in $(MOZ_CHROME_MULTILOCALE) ;\

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

@ -54,8 +54,8 @@ $(DIST)/branding:
libs::
@if test -f "$(LOCALE_SRCDIR)/existing-profile-defaults.js"; then \
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
$(LOCALE_SRCDIR)/existing-profile-defaults.js > $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \
$(PYTHON) -m mozbuild.action.preprocessor $(PREF_PPFLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) \
$(LOCALE_SRCDIR)/existing-profile-defaults.js -o $(FINAL_TARGET)/defaults/existing-profile-defaults.js; \
fi
NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD))

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

@ -144,7 +144,7 @@ ifndef LIBXUL_SDK
# channel-prefs.js is handled separate from other prefs due to bug 756325
libs:: $(srcdir)/profile/channel-prefs.js
$(NSINSTALL) -D $(DIST)/bin/defaults/pref
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(PREF_PPFLAGS) $(ACDEFINES) $^ > $(DIST)/bin/defaults/pref/channel-prefs.js
$(call py_action,preprocessor,$(PREF_PPFLAGS) $(ACDEFINES) $^ -o $(DIST)/bin/defaults/pref/channel-prefs.js)
endif
libs:: $(srcdir)/blocklist.xml

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

@ -61,9 +61,6 @@
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
// Focus the location bar
mainWindow.focusAndSelectUrlBar();
function setFavIcon(url) {
var icon = document.createElement("link");
icon.setAttribute("rel", "icon");

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

@ -79,7 +79,7 @@ ifdef MOZ_PKG_MANIFEST_P
MOZ_PKG_MANIFEST = package-manifest
$(MOZ_PKG_MANIFEST): $(MOZ_PKG_MANIFEST_P) $(GLOBAL_DEPS)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $< > $@
$(call py_action,preprocessor,$(DEFINES) $(ACDEFINES) $< -o $@)
GARBAGE += $(MOZ_PKG_MANIFEST)
endif

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

@ -71,8 +71,8 @@ uninstaller::
$(MKDIR) $(CONFIG_DIR)
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
$(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi)
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
--preprocess-locale $(topsrcdir) \
$(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR)
@ -81,8 +81,8 @@ uninstaller::
ifdef MOZ_MAINTENANCE_SERVICE
maintenanceservice_installer::
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
$(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi)
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
--preprocess-locale $(topsrcdir) \
$(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR)
@ -93,8 +93,8 @@ $(CONFIG_DIR)/setup.exe::
$(MKDIR) $(CONFIG_DIR)
$(INSTALL) $(addprefix $(srcdir)/,$(INSTALLER_FILES)) $(CONFIG_DIR)
$(INSTALL) $(addprefix $(DIST)/branding/,$(BRANDING_FILES)) $(CONFIG_DIR)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py -Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in > $(CONFIG_DIR)/defines.nsi
$(call py_action,preprocessor,-Fsubstitution $(DEFINES) $(ACDEFINES) \
$(srcdir)/nsis/defines.nsi.in -o $(CONFIG_DIR)/defines.nsi)
$(PYTHON) $(topsrcdir)/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py \
--preprocess-locale $(topsrcdir) \
$(PPL_LOCALE_ARGS) $(AB_CD) $(CONFIG_DIR)

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

@ -105,12 +105,11 @@ PROFILE_CHROME = userChrome-example.css userContent-example.css
NO_JA_JP_MAC_AB_CD := $(if $(filter ja-JP-mac, $(AB_CD)),ja,$(AB_CD))
%/defaults/profile/bookmarks.html: bookmarks.inc generic/profile/bookmarks.html.in
$(SYSINSTALL) -D $(dir $@)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
$(call py_action,preprocessor, \
-I $< \
-DAB_CD=$(NO_JA_JP_MAC_AB_CD) \
$(srcdir)/generic/profile/bookmarks.html.in \
> $@
-o $@)
libs:: $(FINAL_TARGET)/defaults/profile/bookmarks.html ;

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

@ -17,7 +17,7 @@ DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
# 'application.ini' breaks firefox build config. So we use something different.
metroapp.ini: metroapp.ini.in $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt
$(RM) "metroapp.ini"
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
$(call py_action,preprocessor,$(DEFINES) $< -o $@)
libs:: metroapp.ini
$(INSTALL) metroapp.ini $(FINAL_TARGET)

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

@ -44,9 +44,9 @@ bookmarks-src = $(srcdir)/../generic/profile/bookmarks.json.in
# processing of the jar file in the parent directory.
bookmarks: bookmarks.inc
@echo "Generating: $@"
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
$(call py_action,preprocessor, \
-I $^ \
-DAB_CD=$(AB_CD) \
$(bookmarks-src) > ../bookmarks.json
$(bookmarks-src) -o ../bookmarks.json)
export:: bookmarks

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

@ -106,7 +106,7 @@ _LEAKTEST_FILES = \
$(NULL)
leaktest.py: leaktest.py.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $^ > $@
$(call py_action,preprocessor,$^ -o $@)
chmod +x $@
GARBAGE += leaktest.py

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

@ -67,7 +67,7 @@ AUTOMATION_PPARGS += -DIS_ASAN=0
endif
automation.py: $(MOZILLA_DIR)/build/automation.py.in $(MOZILLA_DIR)/build/automation-build.mk
$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py \
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< > $@
$(call py_action,preprocessor, \
$(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@)
GARBAGE += automation.py automation.pyc

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

@ -6,7 +6,7 @@ Text Preprocessor
The build system contains a text preprocessor similar to the C preprocessor,
meant for processing files which have no built-in preprocessor such as XUL
and JavaScript documents. It is implemented at ``config/Preprocessor.py`` and
and JavaScript documents. It is implemented at ``python/mozbuild/mozbuild/preprocessor.py`` and
is typically invoked via :ref:`jar_manifests`.
While used to preprocess CSS files, the directives are changed to begin with

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

@ -489,7 +489,8 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
fileName,
scriptSample,
lineNum);
lineNum,
EmptyString());
}
return evalOK;

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

@ -1,241 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Parses and evaluates simple statements for Preprocessor:
Expression currently supports the following grammar, whitespace is ignored:
expression :
and_cond ( '||' expression ) ? ;
and_cond:
test ( '&&' and_cond ) ? ;
test:
unary ( ( '==' | '!=' ) unary ) ? ;
unary :
'!'? value ;
value :
[0-9]+ # integer
| 'defined(' \w+ ')'
| \w+ # string identifier or value;
"""
import re
class Expression:
def __init__(self, expression_string):
"""
Create a new expression with this string.
The expression will already be parsed into an Abstract Syntax Tree.
"""
self.content = expression_string
self.offset = 0
self.__ignore_whitespace()
self.e = self.__get_logical_or()
if self.content:
raise Expression.ParseError, self
def __get_logical_or(self):
"""
Production: and_cond ( '||' expression ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("logical_op")
# test
rv.append(self.__get_logical_and())
self.__ignore_whitespace()
if self.content[:2] != '||':
# no logical op needed, short cut to our prime element
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_logical_or())
self.__ignore_whitespace()
return rv
def __get_logical_and(self):
"""
Production: test ( '&&' and_cond ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("logical_op")
# test
rv.append(self.__get_equality())
self.__ignore_whitespace()
if self.content[:2] != '&&':
# no logical op needed, short cut to our prime element
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_logical_and())
self.__ignore_whitespace()
return rv
def __get_equality(self):
"""
Production: unary ( ( '==' | '!=' ) unary ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("equality")
# unary
rv.append(self.__get_unary())
self.__ignore_whitespace()
if not re.match('[=!]=', self.content):
# no equality needed, short cut to our prime unary
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_unary())
self.__ignore_whitespace()
return rv
def __get_unary(self):
"""
Production: '!'? value
"""
# eat whitespace right away, too
not_ws = re.match('!\s*', self.content)
if not not_ws:
return self.__get_value()
rv = Expression.__AST('not')
self.__strip(not_ws.end())
rv.append(self.__get_value())
self.__ignore_whitespace()
return rv
def __get_value(self):
"""
Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ )
Note that the order is important, and the expression is kind-of
ambiguous as \w includes 0-9. One could make it unambiguous by
removing 0-9 from the first char of a string literal.
"""
rv = None
m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content)
if m:
word_len = m.end()
rv = Expression.__ASTLeaf('defined', m.group(1))
else:
word_len = re.match('[0-9]*', self.content).end()
if word_len:
value = int(self.content[:word_len])
rv = Expression.__ASTLeaf('int', value)
else:
word_len = re.match('\w*', self.content).end()
if word_len:
rv = Expression.__ASTLeaf('string', self.content[:word_len])
else:
raise Expression.ParseError, self
self.__strip(word_len)
self.__ignore_whitespace()
return rv
def __ignore_whitespace(self):
ws_len = re.match('\s*', self.content).end()
self.__strip(ws_len)
return
def __strip(self, length):
"""
Remove a given amount of chars from the input and update
the offset.
"""
self.content = self.content[length:]
self.offset += length
def evaluate(self, context):
"""
Evaluate the expression with the given context
"""
# Helper function to evaluate __get_equality results
def eval_equality(tok):
left = opmap[tok[0].type](tok[0])
right = opmap[tok[2].type](tok[2])
rv = left == right
if tok[1].value == '!=':
rv = not rv
return rv
# Helper function to evaluate __get_logical_and and __get_logical_or results
def eval_logical_op(tok):
left = opmap[tok[0].type](tok[0])
right = opmap[tok[2].type](tok[2])
if tok[1].value == '&&':
return left and right
elif tok[1].value == '||':
return left or right
raise Expression.ParseError, self
# Mapping from token types to evaluator functions
# Apart from (non-)equality, all these can be simple lambda forms.
opmap = {
'logical_op': eval_logical_op,
'equality': eval_equality,
'not': lambda tok: not opmap[tok[0].type](tok[0]),
'string': lambda tok: context[tok.value],
'defined': lambda tok: tok.value in context,
'int': lambda tok: tok.value}
return opmap[self.e.type](self.e);
class __AST(list):
"""
Internal class implementing Abstract Syntax Tree nodes
"""
def __init__(self, type):
self.type = type
super(self.__class__, self).__init__(self)
class __ASTLeaf:
"""
Internal class implementing Abstract Syntax Tree leafs
"""
def __init__(self, type, value):
self.value = value
self.type = type
def __str__(self):
return self.value.__str__()
def __repr__(self):
return self.value.__repr__()
class ParseError(StandardError):
"""
Error raised when parsing fails.
It has two members, offset and content, which give the offset of the
error and the offending content.
"""
def __init__(self, expression):
self.offset = expression.offset
self.content = expression.content[:3]
def __str__(self):
return 'Unexpected content at offset {0}, "{1}"'.format(self.offset,
self.content)
class Context(dict):
"""
This class holds variable values by subclassing dict, and while it
truthfully reports True and False on
name in context
it returns the variable name itself on
context["name"]
to reflect the ambiguity between string literals and preprocessor
variables.
"""
def __getitem__(self, key):
if key in self:
return super(self.__class__, self).__getitem__(key)
return key

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

@ -74,7 +74,7 @@ export-preqs = \
$(NULL)
export:: $(export-preqs)
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
$(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) $(ACDEFINES) \
-DMOZ_TREE_CAIRO=$(MOZ_TREE_CAIRO) \
-DMOZ_TREE_PIXMAN=$(MOZ_TREE_PIXMAN) \
-DMOZ_NATIVE_HUNSPELL=$(MOZ_NATIVE_HUNSPELL) \

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

@ -53,7 +53,7 @@ else
REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^))
endif
else
REPORT_BUILD = $(info $(notdir $@))
REPORT_BUILD = $(info $(if $(filter $(DEPTH)/%,$@),$(@:$(DEPTH)/%=%),$(notdir $@)))
endif
ifeq ($(OS_ARCH),OS2)
@ -1481,6 +1481,11 @@ endif
#
# Additionally, a FOO_TARGET variable may be added to indicate the target for
# which the files and executables are installed. Default is "libs".
#
# Finally, a FOO_KEEP_PATH variable may be set to 1 to indicate the paths given
# in FOO_FILES/FOO_EXECUTABLES are to be kept at the destination. That is,
# if FOO_FILES is bar/baz/qux.h, and FOO_DEST is $(DIST)/include, the installed
# file would be $(DIST)/include/bar/baz/qux.h instead of $(DIST)/include/qux.h
# If we're using binary nsinstall and it's not built yet, fallback to python nsinstall.
ifneq (,$(filter $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX),$(install_cmd)))
@ -1493,22 +1498,52 @@ endef
endif
endif
define install_file_template
$(or $(3),libs):: $(2)/$(notdir $(1))
$(call install_cmd_override,$(2)/$(notdir $(1)))
$(2)/$(notdir $(1)): $(1)
$$(call install_cmd,$(4) "$$<" "$${@D}")
install_target_tier = $(or $($(1)_TARGET),libs)
INSTALL_TARGETS_TIERS := $(sort $(foreach category,$(INSTALL_TARGETS),$(call install_target_tier,$(category))))
install_target_result = $($(1)_DEST:%/=%)/$(if $($(1)_KEEP_PATH),$(2),$(notdir $(2)))
install_target_files = $(foreach file,$($(1)_FILES),$(call install_target_result,$(category),$(file)))
install_target_executables = $(foreach file,$($(1)_EXECUTABLES),$(call install_target_result,$(category),$(file)))
# Work around a GNU make 3.81 bug where it gives $< the wrong value.
# See details in bug 934864.
define create_dependency
$(1): $(2)
$(1): $(2)
endef
define install_target_template
$(call install_cmd_override,$(2))
$(call create_dependency,$(2),$(1))
endef
$(foreach category,$(INSTALL_TARGETS),\
$(if $($(category)_DEST),,$(error Missing $(category)_DEST))\
$(foreach file,$($(category)_FILES),\
$(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS1)))\
)\
$(foreach file,$($(category)_EXECUTABLES),\
$(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS2)))\
)\
$(if $($(category)_DEST),,$(error Missing $(category)_DEST)) \
$(foreach tier,$(call install_target_tier,$(category)),\
$(eval INSTALL_TARGETS_FILES_$(tier) += $(call install_target_files,$(category))) \
$(eval INSTALL_TARGETS_EXECUTABLES_$(tier) += $(call install_target_executables,$(category))) \
) \
$(foreach file,$($(category)_FILES) $($(category)_EXECUTABLES), \
$(eval $(call install_target_template,$(file),$(call install_target_result,$(category),$(file)))) \
) \
)
$(foreach tier,$(INSTALL_TARGETS_TIERS), \
$(eval $(tier):: $(INSTALL_TARGETS_FILES_$(tier)) $(INSTALL_TARGETS_EXECUTABLES_$(tier))) \
)
install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error Looks like $@ has an unexpected dependency on $< which breaks INSTALL_TARGETS))
$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))):
$(install_targets_sanity)
$(REPORT_BUILD)
$(call install_cmd,$(IFLAGS1) "$<" "$(@D)")
$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))):
$(install_targets_sanity)
$(REPORT_BUILD)
$(call install_cmd,$(IFLAGS2) "$<" "$(@D)")
################################################################################
# Preprocessing rules
#
@ -1524,40 +1559,80 @@ $(foreach category,$(INSTALL_TARGETS),\
# If PP_TARGETS lists a category name <C> (like FOO, above), then we consult the
# following make variables to see what to do:
#
# - <C> lists input files to be preprocessed with config/Preprocessor.py. We
# search VPATH for the names given here. If an input file name ends in '.in',
# that suffix is omitted from the output file name.
# - <C> lists input files to be preprocessed with mozbuild.action.preprocessor.
# We search VPATH for the names given here. If an input file name ends in
# '.in', that suffix is omitted from the output file name.
#
# - <C>_PATH names the directory in which to place the preprocessed output
# files. We create this directory if it does not already exist. Setting
# this variable is optional; if unset, we install the files in $(CURDIR).
#
# - <C>_FLAGS lists flags to pass to Preprocessor.py, in addition to the usual
# bunch. Setting this variable is optional.
# - <C>_FLAGS lists flags to pass to mozbuild.action.preprocessor, in addition
# to the usual bunch. Setting this variable is optional.
#
# - <C>_TARGET names the 'make' target that should depend on creating the output
# files. Setting this variable is optional; if unset, we preprocess the
# files for the 'libs' target.
#
# - <C>_KEEP_PATH may be set to 1 to indicate the paths given in <C> are to be
# kept under <C>_PATH. That is, if <C> is bar/baz/qux.h.in and <C>_PATH is
# $(DIST)/include, the preprocessed file would be $(DIST)/include/bar/baz/qux.h
# instead of $(DIST)/include/qux.h.
# preprocess_file_template defines preprocessing rules.
# $(call preprocess_file_template, source_file, output_file,
# makefile_target, extra_flags)
define preprocess_file_template
$(2): $(1) $$(GLOBAL_DEPS)
$$(RM) "$$@"
$$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(4) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) "$$<" -o "$$@"
$(3):: $(2)
endef
pp_target_tier = $(or $($(1)_TARGET),libs)
PP_TARGETS_TIERS := $(sort $(foreach category,$(PP_TARGETS),$(call pp_target_tier,$(category))))
$(foreach category,$(PP_TARGETS), \
$(foreach file,$($(category)), \
$(eval $(call preprocess_file_template, \
$(file), \
$(or $($(category)_PATH),$(CURDIR))/$(notdir $(file:.in=)), \
$(or $($(category)_TARGET),libs), \
$($(category)_FLAGS))) \
) \
)
pp_target_result = $(or $($(1)_PATH:%/=%),$(CURDIR))/$(if $($(1)_KEEP_PATH),$(2:.in=),$(notdir $(2:.in=)))
pp_target_results = $(foreach file,$($(1)),$(call pp_target_result,$(category),$(file)))
$(foreach category,$(PP_TARGETS), \
$(foreach tier,$(call pp_target_tier,$(category)), \
$(eval PP_TARGETS_RESULTS_$(tier) += $(call pp_target_results,$(category))) \
) \
$(foreach file,$($(category)), \
$(eval $(call create_dependency,$(call pp_target_result,$(category),$(file)), \
$(file) $(GLOBAL_DEPS))) \
) \
$(eval $(call pp_target_results,$(category)): PP_TARGET_FLAGS=$($(category)_FLAGS)) \
)
$(foreach tier,$(PP_TARGETS_TIERS), \
$(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \
)
PP_TARGETS_ALL_RESULTS := $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier))))
$(PP_TARGETS_ALL_RESULTS):
$(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS))
$(REPORT_BUILD)
$(RM) "$@"
$(call py_action,preprocessor,--depend $(MDDEPDIR)/$(@F).pp $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@")
# The depfile is based on the filename, and we don't want conflicts. So check
# there's only one occurrence of any given filename in PP_TARGETS_ALL_RESULTS.
PP_TARGETS_ALL_RESULT_NAMES := $(notdir $(PP_TARGETS_ALL_RESULTS))
$(foreach file,$(sort $(PP_TARGETS_ALL_RESULT_NAMES)), \
$(if $(filter-out 1,$(words $(filter $(file),$(PP_TARGETS_ALL_RESULT_NAMES)))), \
$(error Multiple preprocessing rules are creating a $(file) file) \
) \
)
ifneq (,$(filter $(PP_TARGETS_TIERS) $(PP_TARGETS_ALL_RESULTS),$(MAKECMDGOALS)))
# If the depfile for a preprocessed file doesn't exist, add a dep to force
# re-preprocessing.
$(foreach file,$(PP_TARGETS_ALL_RESULTS), \
$(if $(wildcard $(MDDEPDIR)/$(notdir $(file)).pp), \
, \
$(eval $(file): FORCE) \
) \
)
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(addsuffix .pp,$(notdir $(PP_TARGETS_ALL_RESULTS))))))
ifneq (,$(MDDEPEND_FILES))
$(call include_deps,$(MDDEPEND_FILES))
endif
endif
# Pull in non-recursive targets if this is a partial tree build.
ifndef TOPLEVEL_BUILD

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

@ -3557,7 +3557,7 @@ MOZ_ARG_WITH_BOOL(system-nspr,
_USE_SYSTEM_NSPR=1 )
if test -n "$_USE_SYSTEM_NSPR"; then
AM_PATH_NSPR(4.9.6, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
AM_PATH_NSPR(4.10.2, [MOZ_NATIVE_NSPR=1], [AC_MSG_ERROR([your don't have NSPR installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSPR"; then
@ -3668,7 +3668,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.15.3, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.15.4, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_NATIVE_NSS"; then

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

@ -15,7 +15,7 @@ interface nsIDocShell;
* one of these per document/principal.
*/
[scriptable, uuid(e5020ec3-1437-46f5-b4eb-8b60766d02c0)]
[scriptable, uuid(781b6511-f1fa-4e2c-8eff-1739d091eb2f)]
interface nsIContentSecurityPolicy : nsISupports
{
@ -104,6 +104,24 @@ interface nsIContentSecurityPolicy : nsISupports
*/
boolean getAllowsInlineStyle(out boolean shouldReportViolations);
/**
* Whether this policy accepts the given nonce
* @param aNonce
* The nonce string to check against the policy
* @param aContentType
* The type of element on which we encountered this nonce
* @param shouldReportViolation
* Whether or not the use of an incorrect nonce should be reported.
* This function always returns "true" for report-only policies, but when
* the report-only policy is violated, shouldReportViolation is true as
* well.
* @return
* Whether or not this nonce is valid
*/
boolean getAllowsNonce(in AString aNonce,
in unsigned long aContentType,
out boolean shouldReportViolation);
/**
* For each violated policy (of type violationType), log policy violation on
* the Error Console and send a report to report-uris present in the violated
@ -117,15 +135,22 @@ interface nsIContentSecurityPolicy : nsISupports
* sample of the violating content (to aid debugging)
* @param lineNum
* source line number of the violation (if available)
* @param aNonce
* (optional) If this is a nonce violation, include the nonce so we can
* recheck to determine which policies were violated and send the
* appropriate reports.
*/
void logViolationDetails(in unsigned short violationType,
in AString sourceFile,
in AString scriptSample,
in int32_t lineNum);
in int32_t lineNum,
[optional] in AString nonce);
const unsigned short VIOLATION_TYPE_INLINE_SCRIPT = 1;
const unsigned short VIOLATION_TYPE_EVAL = 2;
const unsigned short VIOLATION_TYPE_INLINE_STYLE = 3;
const unsigned short VIOLATION_TYPE_EVAL = 2;
const unsigned short VIOLATION_TYPE_INLINE_STYLE = 3;
const unsigned short VIOLATION_TYPE_NONCE_SCRIPT = 4;
const unsigned short VIOLATION_TYPE_NONCE_STYLE = 5;
/**
* Called after the CSP object is created to fill in the appropriate request

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

@ -2171,6 +2171,9 @@ public:
virtual nsHTMLDocument* AsHTMLDocument() { return nullptr; }
virtual JSObject* WrapObject(JSContext *aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
private:
uint64_t mWarnedAbout;
SelectorCache mSelectorCache;

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

@ -24,7 +24,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "Services",
// Module stuff
this.EXPORTED_SYMBOLS = ["CSPRep", "CSPSourceList", "CSPSource", "CSPHost",
"CSPdebug", "CSPViolationReportListener", "CSPLocalizer"];
"CSPdebug", "CSPViolationReportListener", "CSPLocalizer",
"CSPPrefObserver"];
var STRINGS_URI = "chrome://global/locale/security/csp.properties";
@ -65,25 +66,37 @@ const R_EXTHOSTSRC = new RegExp ("^" + R_HOSTSRC.source + "\\/[:print:]+$", 'i')
// keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'"
const R_KEYWORDSRC = new RegExp ("^('self'|'unsafe-inline'|'unsafe-eval')$", 'i');
// nonce-source = "'nonce-" nonce-value "'"
// nonce-value = 1*( ALPHA / DIGIT / "+" / "/" )
const R_NONCESRC = new RegExp ("^'nonce-([a-zA-Z0-9\+\/]+)'$", 'i');
// source-exp = scheme-source / host-source / keyword-source
const R_SOURCEEXP = new RegExp (R_SCHEMESRC.source + "|" +
R_HOSTSRC.source + "|" +
R_KEYWORDSRC.source, 'i');
R_KEYWORDSRC.source + "|" +
R_NONCESRC.source, 'i');
var gPrefObserver = {
this.CSPPrefObserver = {
get debugEnabled () {
if (!this._branch)
this._initialize();
return this._debugEnabled;
},
get experimentalEnabled () {
if (!this._branch)
this._initialize();
return this._experimentalEnabled;
},
_initialize: function() {
var prefSvc = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefService);
this._branch = prefSvc.getBranch("security.csp.");
this._branch.addObserver("", this, false);
this._debugEnabled = this._branch.getBoolPref("debug");
this._experimentalEnabled = this._branch.getBoolPref("experimentalEnabled");
},
unregister: function() {
@ -95,11 +108,13 @@ var gPrefObserver = {
if (aTopic != "nsPref:changed") return;
if (aData === "debug")
this._debugEnabled = this._branch.getBoolPref("debug");
if (aData === "experimentalEnabled")
this._experimentalEnabled = this._branch.getBoolPref("experimentalEnabled");
},
};
this.CSPdebug = function CSPdebug(aMsg) {
if (!gPrefObserver.debugEnabled) return;
if (!CSPPrefObserver.debugEnabled) return;
aMsg = 'CSP debug: ' + aMsg + "\n";
Components.classes["@mozilla.org/consoleservice;1"]
@ -793,14 +808,28 @@ CSPRep.prototype = {
/**
* Determines if this policy accepts a URI.
* @param aContext
* @param aURI
* URI of the requested resource
* @param aDirective
* one of the SRC_DIRECTIVES defined above
* @param aContext
* Context of the resource being requested. This is a type inheriting
* from nsIDOMHTMLElement if this is called from shouldLoad to check
* an external resource load, and refers to the HTML element that is
* causing the resource load. Otherwise, it is a string containing
* a nonce from a nonce="" attribute if it is called from
* getAllowsNonce.
* @returns
* true if the policy permits the URI in given context.
*/
permits:
function csp_permits(aURI, aContext) {
if (!aURI) return false;
function csp_permits(aURI, aDirective, aContext) {
// In the case where permits is called from getAllowsNonce (for an inline
// element), aURI is null and aContext has a specific value. Otherwise,
// calling permits without aURI is invalid.
let checking_nonce = aContext instanceof Ci.nsIDOMHTMLElement ||
typeof aContext === 'string';
if (!aURI && !checking_nonce) return false;
// GLOBALLY ALLOW "about:" SCHEME
if (aURI instanceof String && aURI.substring(0,6) === "about:")
@ -811,13 +840,13 @@ CSPRep.prototype = {
// make sure the right directive set is used
let DIRS = this._specCompliant ? CSPRep.SRC_DIRECTIVES_NEW : CSPRep.SRC_DIRECTIVES_OLD;
let contextIsSrcDir = false;
let directiveInPolicy = false;
for (var i in DIRS) {
if (DIRS[i] === aContext) {
if (DIRS[i] === aDirective) {
// for catching calls with invalid contexts (below)
contextIsSrcDir = true;
if (this._directives.hasOwnProperty(aContext)) {
return this._directives[aContext].permits(aURI);
directiveInPolicy = true;
if (this._directives.hasOwnProperty(aDirective)) {
return this._directives[aDirective].permits(aURI, aContext);
}
//found matching dir, can stop looking
break;
@ -825,15 +854,15 @@ CSPRep.prototype = {
}
// frame-ancestors is a special case; it doesn't fall back to default-src.
if (aContext === DIRS.FRAME_ANCESTORS)
if (aDirective === DIRS.FRAME_ANCESTORS)
return true;
// All directives that don't fall back to default-src should have an escape
// hatch above (like frame-ancestors).
if (!contextIsSrcDir) {
if (!directiveInPolicy) {
// if this code runs, there's probably something calling permits() that
// shouldn't be calling permits().
CSPdebug("permits called with invalid load type: " + aContext);
CSPdebug("permits called with invalid load type: " + aDirective);
return false;
}
@ -842,7 +871,7 @@ CSPRep.prototype = {
// indicates no relevant directives were present and the load should be
// permitted).
if (this._directives.hasOwnProperty(DIRS.DEFAULT_SRC)) {
return this._directives[DIRS.DEFAULT_SRC].permits(aURI);
return this._directives[DIRS.DEFAULT_SRC].permits(aURI, aContext);
}
// no relevant directives present -- this means for CSP 1.0 that the load
@ -1081,12 +1110,12 @@ CSPSourceList.prototype = {
* true if the URI matches a source in this source list.
*/
permits:
function cspsd_permits(aURI) {
function cspsd_permits(aURI, aContext) {
if (this.isNone()) return false;
if (this.isAll()) return true;
for (var i in this._sources) {
if (this._sources[i].permits(aURI)) {
if (this._sources[i].permits(aURI, aContext)) {
return true;
}
}
@ -1102,6 +1131,7 @@ this.CSPSource = function CSPSource() {
this._scheme = undefined;
this._port = undefined;
this._host = undefined;
this._nonce = undefined;
//when set to true, this allows all source
this._permitAll = false;
@ -1346,6 +1376,19 @@ CSPSource.fromString = function(aStr, aCSPRep, self, enforceSelfChecks) {
return sObj;
}
// check for a nonce-source match
if (R_NONCESRC.test(aStr)) {
// We can't put this check outside of the regex test because R_NONCESRC is
// included in R_SOURCEEXP, which is const. By testing here, we can
// explicitly return null for nonces if experimental is not enabled,
// instead of letting it fall through and assuming it won't accidentally
// match something later in this function.
if (!CSPPrefObserver.experimentalEnabled) return null;
var nonceSrcMatch = R_NONCESRC.exec(aStr);
sObj._nonce = nonceSrcMatch[1];
return sObj;
}
// check for 'self' (case insensitive)
if (aStr.toUpperCase() === "'SELF'") {
if (!self) {
@ -1450,6 +1493,8 @@ CSPSource.prototype = {
s = s + this._host;
if (this.port)
s = s + ":" + this.port;
if (this._nonce)
s = s + "'nonce-" + this._nonce + "'";
return s;
},
@ -1465,6 +1510,7 @@ CSPSource.prototype = {
aClone._scheme = this._scheme;
aClone._port = this._port;
aClone._host = this._host ? this._host.clone() : undefined;
aClone._nonce = this._nonce;
aClone._isSelf = this._isSelf;
aClone._CSPRep = this._CSPRep;
return aClone;
@ -1474,11 +1520,24 @@ CSPSource.prototype = {
* Determines if this Source accepts a URI.
* @param aSource
* the URI, or CSPSource in question
* @param aContext
* the context of the resource being loaded
* @returns
* true if the URI matches a source in this source list.
*/
permits:
function(aSource) {
function(aSource, aContext) {
if (this._nonce && CSPPrefObserver.experimentalEnabled) {
if (aContext instanceof Ci.nsIDOMHTMLElement) {
return this._nonce === aContext.getAttribute('nonce');
} else if (typeof aContext === 'string') {
return this._nonce === aContext;
}
}
// We only use aContext for nonce checks. If it's otherwise provided,
// ignore it.
if (!CSPPrefObserver.experimentalEnabled && aContext) return false;
if (!aSource) return false;
if (!(aSource instanceof CSPSource))

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

@ -31,6 +31,8 @@ const ERROR_FLAG = Ci.nsIScriptError.ERROR_FLAG;
const INLINE_STYLE_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Inline Stylesheets will not apply';
const INLINE_SCRIPT_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Inline Scripts will not execute';
const EVAL_VIOLATION_OBSERVER_SUBJECT = 'violated base restriction: Code will not be created from strings';
const SCRIPT_NONCE_VIOLATION_OBSERVER_SUBJECT = 'Inline Script had invalid nonce'
const STYLE_NONCE_VIOLATION_OBSERVER_SUBJECT = 'Inline Style had invalid nonce'
// The cutoff length of content location in creating CSP cache key.
const CSP_CACHE_URI_CUTOFF_SIZE = 512;
@ -189,6 +191,28 @@ ContentSecurityPolicy.prototype = {
});
},
getAllowsNonce: function(aNonce, aContentType, shouldReportViolation) {
if (!CSPPrefObserver.experimentalEnabled)
return false;
if (!(aContentType == Ci.nsIContentPolicy.TYPE_SCRIPT ||
aContentType == Ci.nsIContentPolicy.TYPE_STYLESHEET)) {
CSPdebug("Nonce check requested for an invalid content type (not script or style): " + aContentType);
return false;
}
let ct = ContentSecurityPolicy._MAPPINGS[aContentType];
// allow it to execute?
let policyAllowsNonce = [ policy.permits(null, ct, aNonce) for (policy of this._policies) ];
shouldReportViolation.value = policyAllowsNonce.some(function(a) { return !a; });
// allow it to execute? (Do all the policies allow it to execute)?
return this._policies.every(function(policy, i) {
return policy._reportOnlyMode || policyAllowsNonce[i];
});
},
/**
* For each policy, log any violation on the Error Console and send a report
* if a report-uri is present in the policy
@ -201,9 +225,13 @@ ContentSecurityPolicy.prototype = {
* sample of the violating content (to aid debugging)
* @param aLineNum
* source line number of the violation (if available)
* @param aNonce
* (optional) If this is a nonce violation, include the nonce should we
* can recheck to determine which policies were violated and send the
* appropriate reports.
*/
logViolationDetails:
function(aViolationType, aSourceFile, aScriptSample, aLineNum, violatedPolicyIndex) {
function(aViolationType, aSourceFile, aScriptSample, aLineNum, aNonce) {
for (let policyIndex=0; policyIndex < this._policies.length; policyIndex++) {
let policy = this._policies[policyIndex];
@ -237,6 +265,24 @@ ContentSecurityPolicy.prototype = {
aSourceFile, aScriptSample, aLineNum);
}
break;
case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_NONCE_SCRIPT:
let scriptType = ContentSecurityPolicy._MAPPINGS[Ci.nsIContentPolicy.TYPE_SCRIPT];
if (!policy.permits(null, scriptType, aNonce)) {
var violatedDirective = this._buildViolatedDirectiveString('SCRIPT_SRC', policy);
this._asyncReportViolation('self', null, violatedDirective, policyIndex,
SCRIPT_NONCE_VIOLATION_OBSERVER_SUBJECT,
aSourceFile, aScriptSample, aLineNum);
}
break;
case Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_NONCE_STYLE:
let styleType = ContentSecurityPolicy._MAPPINGS[Ci.nsIContentPolicy.TYPE_STYLE];
if (!policy.permits(null, styleType, aNonce)) {
var violatedDirective = this._buildViolatedDirectiveString('STYLE_SRC', policy);
this._asyncReportViolation('self', null, violatedDirective, policyIndex,
STYLE_NONCE_VIOLATION_OBSERVER_SUBJECT,
aSourceFile, aScriptSample, aLineNum);
}
break;
}
}
},
@ -628,6 +674,14 @@ ContentSecurityPolicy.prototype = {
let cp = Ci.nsIContentPolicy;
// Infer if this is a preload for elements that use nonce-source. Since,
// for preloads, aContext is the document and not the element associated
// with the resource, we cannot determine the nonce. See Bug 612921 and
// Bug 855326.
var possiblePreloadNonceConflict =
(aContentType == cp.TYPE_SCRIPT || aContentType == cp.TYPE_STYLESHEET) &&
aContext instanceof Ci.nsIDOMHTMLDocument;
// iterate through all the _policies and send reports where a policy is
// violated. After the check, determine the overall effect (blocked or
// loaded?) and cache it.
@ -661,15 +715,18 @@ ContentSecurityPolicy.prototype = {
// otherwise, honor the translation
// var source = aContentLocation.scheme + "://" + aContentLocation.hostPort;
var res = policy.permits(aContentLocation, cspContext)
? cp.ACCEPT : cp.REJECT_SERVER;
let context = CSPPrefObserver.experimentalEnabled ? aContext : null;
var res = policy.permits(aContentLocation, cspContext, context) ?
cp.ACCEPT : cp.REJECT_SERVER;
// record whether the thing should be blocked or just reported.
policyAllowsLoadArray.push(res == cp.ACCEPT || policy._reportOnlyMode);
// frame-ancestors is taken care of early on (as this document is loaded)
// If the result is *NOT* ACCEPT, then send report
if (res != Ci.nsIContentPolicy.ACCEPT) {
// Do not send report if this is a nonce-source preload - the decision may
// be wrong and will incorrectly fail the unit tests.
if (res != Ci.nsIContentPolicy.ACCEPT && !possiblePreloadNonceConflict) {
CSPdebug("blocking request for " + aContentLocation.asciiSpec);
try {
let directive = "unknown directive",
@ -704,7 +761,8 @@ ContentSecurityPolicy.prototype = {
let ret = (policyAllowsLoadArray.some(function(a,b) { return !a; }) ?
cp.REJECT_SERVER : cp.ACCEPT);
if (key) {
// Do not cache the result if this is a nonce-source preload
if (key && !possiblePreloadNonceConflict) {
this._cache[key] = ret;
}
return ret;

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

@ -11329,6 +11329,57 @@ nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
aInResult, aResult);
}
// This is just a hack around the fact that window.document is not
// [Unforgeable] yet.
JSObject*
nsIDocument::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aScope)
{
MOZ_ASSERT(IsDOMBinding());
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aScope));
if (!obj) {
return nullptr;
}
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetInnerWindow());
if (!win) {
// No window, nothing else to do here
return obj;
}
if (this != win->GetExtantDoc()) {
// We're not the current document; we're also done here
return obj;
}
JSAutoCompartment ac(aCx, obj);
JS::Rooted<JS::Value> winVal(aCx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = nsContentUtils::WrapNative(aCx, obj, win,
&NS_GET_IID(nsIDOMWindow),
&winVal,
getter_AddRefs(holder),
false);
if (NS_FAILED(rv)) {
Throw(aCx, rv);
return nullptr;
}
NS_NAMED_LITERAL_STRING(doc_str, "document");
if (!JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal),
reinterpret_cast<const jschar *>
(doc_str.get()),
doc_str.Length(), JS::ObjectValue(*obj),
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_READONLY | JSPROP_ENUMERATE)) {
return nullptr;
}
return obj;
}
XPathEvaluator*
nsIDocument::XPathEvaluator()
{

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

@ -608,6 +608,7 @@ GK_ATOM(nodeSet, "node-set")
GK_ATOM(noembed, "noembed")
GK_ATOM(noframes, "noframes")
GK_ATOM(nohref, "nohref")
GK_ATOM(nonce, "nonce")
GK_ATOM(none, "none")
GK_ATOM(noresize, "noresize")
GK_ATOM(normal, "normal")

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

@ -47,13 +47,7 @@ nsNodeInfoManager::GetNodeInfoInnerHashValue(const void *key)
const nsINodeInfo::nsNodeInfoInner *node =
reinterpret_cast<const nsINodeInfo::nsNodeInfoInner *>(key);
if (node->mName) {
// Ideally, we'd return node->mName->hash() here. But that doesn't work at
// the moment because node->mName->hash() is not the same as
// HashString(*(node->mNameString)). See bug 732815.
return HashString(nsDependentAtomString(node->mName));
}
return HashString(*(node->mNameString));
return node->mName ? node->mName->hash() : HashString(*(node->mNameString));
}

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

@ -624,13 +624,31 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
NS_ENSURE_SUCCESS(rv, false);
if (csp) {
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****"));
bool inlineOK = true;
bool reportViolations = false;
rv = csp->GetAllowsInlineScript(&reportViolations, &inlineOK);
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader ****with CSP****"));
bool reportViolation = false;
bool allowInlineScript = true;
rv = csp->GetAllowsInlineScript(&reportViolation, &allowInlineScript);
NS_ENSURE_SUCCESS(rv, false);
if (reportViolations) {
bool foundNonce = false;
nsAutoString nonce;
if (!allowInlineScript) {
foundNonce = scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
if (foundNonce) {
// We can overwrite the outparams from GetAllowsInlineScript because
// if the nonce is correct, then we don't want to report the original
// inline violation (it has been whitelisted by the nonce), and if
// the nonce is incorrect, then we want to return just the specific
// "nonce violation" rather than both a "nonce violation" and
// a generic "inline violation".
rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_SCRIPT,
&reportViolation, &allowInlineScript);
NS_ENSURE_SUCCESS(rv, false);
}
}
if (reportViolation) {
// gather information to log with violation report
nsIURI* uri = mDocument->GetDocumentURI();
nsAutoCString asciiSpec;
@ -641,17 +659,21 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
// cap the length of the script sample at 40 chars
if (scriptText.Length() > 40) {
scriptText.Truncate(40);
scriptText.Append(NS_LITERAL_STRING("..."));
scriptText.AppendLiteral("...");
}
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
NS_ConvertUTF8toUTF16(asciiSpec),
scriptText,
aElement->GetScriptLineNumber());
// The type of violation to report is determined by whether there was
// a nonce present.
unsigned short violationType = foundNonce ?
nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_SCRIPT :
nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT;
csp->LogViolationDetails(violationType, NS_ConvertUTF8toUTF16(asciiSpec),
scriptText, aElement->GetScriptLineNumber(), nonce);
}
if (!inlineOK) {
PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts (2)"));
if (!allowInlineScript) {
NS_ASSERTION(reportViolation,
"CSP blocked inline script but is not reporting a violation");
return false;
}
}

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

@ -360,7 +360,10 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
nsAutoString text;
nsContentUtils::GetNodeTextContent(thisContent, false, text);
if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->NodePrincipal(),
MOZ_ASSERT(thisContent->Tag() != nsGkAtoms::link,
"<link> is not 'inline', and needs different CSP checks");
if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent,
thisContent->NodePrincipal(),
doc->GetDocumentURI(),
mLineNumber, text, &rv))
return rv;

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

@ -236,7 +236,7 @@ nsStyledElementNotElementCSSInlineStyle::ParseStyleAttribute(const nsAString& aV
{
nsIDocument* doc = OwnerDoc();
if (!nsStyleUtil::CSPAllowsInlineStyle(NodePrincipal(),
if (!nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(),
doc->GetDocumentURI(), 0, aValue,
nullptr))
return;

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

@ -0,0 +1,67 @@
<!doctype html>
<html>
<head>
<!-- external styles -->
<link rel='stylesheet' nonce="correctstylenonce" href="file_CSP.sjs?testid=external_style_correct_nonce_good&type=text/css" />
<link rel='stylesheet' nonce="incorrectstylenonce" href="file_CSP.sjs?testid=external_style_incorrect_nonce_bad&type=text/css" />
<link rel='stylesheet' nonce="correctscriptnonce" href="file_CSP.sjs?testid=external_style_correct_script_nonce_bad&type=text/css" />
<link rel='stylesheet' href="file_CSP.sjs?testid=external_style_no_nonce_bad&type=text/css" />
</head>
<body>
<!-- inline scripts -->
<script nonce="correctscriptnonce">
window.parent.inlineScriptTestResult("allowed", "allowed", "This script has a correct nonce for scripts");
</script>
<script nonce="incorrectscriptnonce">
window.parent.inlineScriptTestResult("allowed", "blocked", "This script has an incorrect nonce for scripts");
</script>
<script nonce="correctstylenonce">
window.parent.inlineScriptTestResult("allowed", "blocked", "This script has a correct nonce for styles (but not for scripts)");
</script>
<script>
window.parent.inlineScriptTestResult("allowed", "blocked", "This script has no nonce");
</script>
<!-- external scripts -->
<script nonce="correctscriptnonce" src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=external_script_correct_nonce_good&type=text/javascript"></script>
<script nonce="anothercorrectscriptnonce" src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=external_script_another_correct_nonce_good&type=text/javascript"></script>
<script nonce="incorrectscriptnonce" src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=external_script_incorrect_nonce_bad&type=text/javascript"></script>
<script nonce="correctstylenonce" src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=external_script_correct_style_nonce_bad&type=text/javascript"></script>
<script src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=external_script_no_nonce_bad&type=text/javascript"></script>
<!-- This external script has the correct nonce and comes from a whitelisted URI. It should be allowed. -->
<script nonce="correctscriptnonce" src="file_CSP.sjs?testid=external_script_correct_nonce_correct_uri_good&type=text/javascript"></script>
<!-- This external script has an incorrect nonce, but comes from a whitelisted URI. It should be allowed. -->
<script nonce="incorrectscriptnonce" src="file_CSP.sjs?testid=external_script_incorrect_nonce_correct_uri_good&type=text/javascript"></script>
<!-- This external script has no nonce and comes from a whitelisted URI. It should be allowed. -->
<script src="file_CSP.sjs?testid=external_script_no_nonce_correct_uri_good&type=text/javascript"></script>
<!-- inline styles -->
<ol>
<li id=inline-style-correct-nonce>
(inline style with correct nonce) This text should be green
</li>
<li id=inline-style-incorrect-nonce>
(inline style with incorrect nonce) This text should be black
</li>
<li id=inline-style-correct-script-nonce>
(inline style with correct script, not style, nonce) This text should be black
</li>
<li id=inline-style-no-nonce>
(inline style with no nonce) This text should be black
</li>
</ol>
<style nonce=correctstylenonce>
li#inline-style-correct-nonce { color: green; }
</style>
<style nonce=incorrectstylenonce>
li#inline-style-incorrect-nonce { color: red; }
</style>
<style nonce=correctscriptnonce>
li#inline-style-correct-script-nonce { color: red; }
</style>
<style>
li#inline-style-no-nonce { color: red; }
</style>
</body>
</html>

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

@ -0,0 +1,2 @@
Content-Security-Policy: script-src 'self' 'nonce-correctscriptnonce' 'nonce-anothercorrectscriptnonce'; style-src 'nonce-correctstylenonce';
Cache-Control: no-cache

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

@ -85,6 +85,8 @@ support-files =
file_policyuri_regression_from_multipolicy.html
file_policyuri_regression_from_multipolicy.html^headers^
file_policyuri_regression_from_multipolicy_policy
file_nonce_source.html
file_nonce_source.html^headers^
[test_CSP.html]
[test_CSP_bug663567.html]
@ -103,3 +105,4 @@ support-files =
[test_CSP_bug910139.html]
[test_CSP_bug909029.html]
[test_policyuri_regression_from_multipolicy.html]
[test_nonce_source.html]

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

@ -0,0 +1,149 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test CSP 1.1 nonce-source for scripts and styles</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="visibility:hidden">
<iframe style="width:100%;" id='cspframe'></iframe>
</div>
<script class="testbody" type="text/javascript">
var testsRun = 0;
var totalTests = 20;
var inlineScriptTestsRun = 0;
var totalInlineScriptTests = 4;
var scriptNonceViolations = 0;
var expectedScriptNonceViolations = 2;
var scriptInlineViolations = 0;
var expectedScriptInlineViolations = 1;
// This is used to watch the blocked data bounce off CSP
function examiner() {
SpecialPowers.addObserver(this, "http-on-modify-request", false);
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
}
examiner.prototype = {
observe: function(subject, topic, data) {
if (!SpecialPowers.can_QI(subject))
return;
var testid_re = new RegExp("testid=([a-z0-9_]+)");
//_good things better be allowed!
//_bad things better be blocked!
if (topic === "http-on-modify-request") {
// these things were allowed by CSP
var allowed_uri = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
if (!testid_re.test(allowed_uri)) return;
var testid = testid_re.exec(allowed_uri)[1];
ok(/_good/.test(testid), "Allowed URI with testid " + testid);
ranTests(1);
}
if (topic === "csp-on-violate-policy") {
try {
// if it is an blocked external load, subject will be the URI of the resource
var blocked_uri = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
if (!testid_re.test(blocked_uri)) return;
var testid = testid_re.exec(blocked_uri)[1];
ok(/_bad/.test(testid), "Blocked URI with testid " + testid);
ranTests(1);
} catch (e) {
// if the subject is blocked inline, data will be a violation msg (defined at the top of contentSecurityPolicy.js)
var violation_msg = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsISupportsCString"), "data");
if (/Inline Script/.test(violation_msg)) {
if (/Inline Script had invalid nonce/.test(violation_msg))
scriptNonceViolations++;
if (/Inline Scripts will not execute/.test(violation_msg))
scriptInlineViolations++;
window.inlineScriptTestResult("blocked", "blocked",
"Blocked because " + violation_msg);
}
}
}
},
// must eventually call this to remove the listener, or mochitests might get borked.
remove: function() {
SpecialPowers.removeObserver(this, "http-on-modify-request");
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
}
}
var inlineScriptTestResult = function(testIs, testShouldBe, description) {
if (testIs !== testShouldBe) {
ok(false, description);
} else {
ok(true, description);
}
ranTests(1)
inlineScriptTestsRun++;
if (inlineScriptTestsRun == totalInlineScriptTests) {
if (scriptNonceViolations != expectedScriptNonceViolations)
ok(false, "The number of reported script nonce violations does not match expected; got " + scriptNonceViolations + ", expected " + expectedScriptNonceViolations);
if (scriptInlineViolations != expectedScriptInlineViolations)
ok(false, "The number of reported inline script violations does not match expected; got " + scriptInlineViolations + ", expected " + expectedScriptInlineViolations);
ranTests(2);
}
}
function cleanup() {
// remove the observer so we don't bork other tests
window.examiner.remove();
// finish the tests
SimpleTest.finish();
}
function ranTests(num) {
testsRun += num;
if (testsRun < totalTests) {
return;
}
cleanup();
}
function checkStyles () {
var cspframe = document.getElementById('cspframe');
var getElementColorById = function (id) {
return window.getComputedStyle(cspframe.contentDocument.getElementById(id), null).color;
};
// Inline style tries to change an element's color to green. If blocked, the
// element's color will be the default black.
var green = "rgb(0, 128, 0)";
var black = "rgb(0, 0, 0)";
is(getElementColorById('inline-style-correct-nonce'), green, "Inline style with correct nonce allowed");
is(getElementColorById('inline-style-incorrect-nonce'), black, "Inline style with incorrect nonce blocked");
is(getElementColorById('inline-style-correct-script-nonce'), black, "Inline style with correct nonce for scripts (but incorrect nonce for styles) blocked");
is(getElementColorById('inline-style-no-nonce'), black, "Inline style with no nonce blocked");
ranTests(4);
}
//////////////////////////////////////////////////////////////////////
// set up and go
window.examiner = new examiner();
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv(
{'set':[["security.csp.speccompliant", true],
["security.csp.experimentalEnabled", true]]},
function() {
// save this for last so that our listeners are registered.
// ... this loads the testbed of good and bad requests.
document.getElementById('cspframe').src = 'file_nonce_source.html';
document.getElementById('cspframe').addEventListener('load', checkStyles, false);
});
</script>
</pre>
</body>
</html>

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

@ -228,10 +228,11 @@ nsEventListenerManager::AddEventListenerInternal(
uint32_t count = mListeners.Length();
for (uint32_t i = 0; i < count; i++) {
ls = &mListeners.ElementAt(i);
if (ls->mListener == aListener &&
ls->mListenerIsHandler == aHandler &&
// mListener == aListener is the last one, since it can be a bit slow.
if (ls->mListenerIsHandler == aHandler &&
ls->mFlags == aFlags &&
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents)) {
EVENT_TYPE_EQUALS(ls, aType, aTypeAtom, aTypeString, aAllEvents) &&
ls->mListener == aListener) {
return;
}
}
@ -728,7 +729,8 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
NS_ConvertUTF8toUTF16(asciiSpec),
scriptSample,
0);
0,
EmptyString());
}
// return early if CSP wants us to block inline scripts

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

@ -35,6 +35,7 @@ MOCHITEST_FILES = test_bug1682.html \
test_viewport.html \
test_documentAll.html \
test_document-element-inserted.html \
test_document.watch.html \
$(filter disabled-temporarily--bug-559932, test_bug445004.html) \
bug445004-inner.js \
bug445004-outer-rel.html \

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

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=903332
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 903332</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 903332 **/
var watch1Called;
function watch1(prop, oldValue, newValue)
{
is(watch1Called, false, "watch1Called not reset properly?");
watch1Called = true;
is(prop, "cookie", "wrong property name passed to watch1");
return newValue;
}
var watch2Called;
function watch2(prop, oldValue, newValue)
{
is(watch2Called, false, "watch2Called not reset properly?");
watch2Called = true;
is(prop, "cookie", "wrong property name passed to watch2");
return newValue;
}
// Just in case subsequent tests depend on a particular value...
var originalValue = document.cookie;
ok(true, "originalValue: " + originalValue);
var originalPrefix = originalValue.length > 0 ? originalValue + "; " : "";
try
{
// trial set (no watch) to verify things work
document.cookie = "first=set";
is(document.cookie, originalPrefix + "first=set",
"first value correct");
// add a watch
document.watch("cookie", watch1);
// set, check for watch invoked
watch1Called = false;
document.cookie = "second=set";
is(watch1Called, true, "watch1 function should be called");
is(document.cookie, originalPrefix + "first=set; second=set",
"second value correct");
// and a second time, just in case
watch1Called = false;
document.cookie = "third=set";
is(watch1Called, true, "watch1 function should be called");
is(document.cookie, originalPrefix + "first=set; second=set; third=set",
"third value correct");
// overwrite the current watch with a new one
document.watch("cookie", watch2);
// set, check for watch invoked
watch1Called = false;
watch2Called = false;
document.cookie = "fourth=set";
is(watch1Called, false, "watch1 invoked erroneously");
is(watch2Called, true, "watch2 function should be called");
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set",
"fourth value correct");
// and a second time, just in case
watch1Called = false;
watch2Called = false;
document.cookie = "fifth=set";
is(watch1Called, false, "watch1 invoked erroneously");
is(watch2Called, true, "watch2 function should be called");
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set",
"fifth value correct");
// remove the watch
document.unwatch("cookie");
// check for non-invocation now
watch1Called = false;
watch2Called = false;
document.cookie = "sixth=set";
is(watch1Called, false, "watch1 shouldn't be called");
is(watch2Called, false, "watch2 shouldn't be called");
is(document.cookie, originalPrefix + "first=set; second=set; third=set; fourth=set; fifth=set; sixth=set",
"sixth value correct");
}
finally
{
// reset
document.unwatch("cookie"); // harmless, should be no-op except if bugs
var d = new Date();
d.setTime(0);
var suffix = "=; expires=" + d.toGMTString();
document.cookie = "first" + suffix;
document.cookie = "second" + suffix;
document.cookie = "third" + suffix;
document.cookie = "fourth" + suffix;
document.cookie = "fifth" + suffix;
document.cookie = "sixth" + suffix;
}
is(document.cookie, originalValue,
"document.cookie isn't what it was initially! expect bustage further " +
"down the line");
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=903332">Mozilla Bug 903332</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

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

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html class="reftest-wait">
<script>
function boom()
{
var ac = new window.AudioContext();
var panner = ac.createPanner();
panner.setPosition(8, 0.7643051305237005, 0.10292575673733972);
var oscillator = ac.createOscillator();
oscillator.connect(panner);
oscillator.start(0);
setTimeout(function() {
panner.panningModel = 'equalpower';
oscillator.stop(0);
document.documentElement.removeAttribute("class");
}, 0.5);
}
boom();
</script>
</html>

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

@ -61,6 +61,7 @@ load 925619-1.html
load 925619-2.html
load 926619.html
load 933151.html
load 933156.html
load offline-buffer-source-ended-1.html
skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338
skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338

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

@ -535,6 +535,8 @@ AudioContext::Shutdown()
Suspend();
mDecoder.Shutdown();
// Release references to active nodes.
// Active AudioNodes don't unregister in destructors, at which point the
// Node is already unregistered.

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

@ -539,6 +539,17 @@ MediaBufferDecoder::EnsureThreadPoolInitialized()
return true;
}
void
MediaBufferDecoder::Shutdown() {
if (mThreadPool) {
// Setting threadLimit to 0 causes threads to exit when all events have
// been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event
// loop nor wait until this has happened.
mThreadPool->SetThreadLimit(0);
mThreadPool = nullptr;
}
}
WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
AudioContext* aContext,
const ArrayBuffer& aBuffer,

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

@ -80,6 +80,8 @@ public:
bool SyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
void Shutdown();
private:
bool EnsureThreadPoolInitialized();

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

@ -27,7 +27,7 @@
//
// Web Audio doesn't provide a means to precisely time connect()s but we can
// test that the output of delay nodes matches the output from a reference
// PannerNodes that we know will not be GCed.
// PannerNode that we know will not be GCed.
//
// Another set of delay nodes is added upstream to ensure that the source node
// has removed its self-reference after dispatching its "ended" event.
@ -41,15 +41,14 @@ const blockSize = 128;
const bufferSize = 4096;
const pannerCount = bufferSize / blockSize;
// sourceDelayBufferCount should be long enough to allow the source node
// onended to finish. Because of the way blocks are processed in sets on
// the graph thread, this also affects when the graph thread receives the
// disconnect.
// onended to finish and remove the source self-reference.
const sourceDelayBufferCount = 3;
var gotEnded = false;
// ccDelayLength should be long enough to allow CC to run
var ccDelayBufferCount = 20;
const ccDelayLength = ccDelayBufferCount * bufferSize;
var ctx;
var testPanners = [];
var referencePanner;
var referenceProcessCount = 0;
@ -58,18 +57,27 @@ var referenceOutput = [new Float32Array(bufferSize),
var testProcessor;
var testProcessCount = 0;
function isChannelSilent(channel) {
for (var i = 0; i < channel.length; ++i) {
if (channel[i] != 0.0) {
dump("input at " + i + "\n");
return false;
}
}
return true;
}
function onReferenceOutput(e) {
switch(referenceProcessCount) {
case sourceDelayBufferCount - 1:
// The panners are about to finish.
if (!gotEnded) {
todo(false, "Oscillator hasn't ended. Increase sourceDelayBufferCount?");
todo(false, "Source hasn't ended. Increase sourceDelayBufferCount?");
}
// Connect each PannerNode output to a downstream DelayNode,
// and connect ScriptProcessors to compare test and reference panners.
var ctx = e.target.context;
var delayDuration = ccDelayLength / ctx.sampleRate;
for (var i = 0; i < pannerCount; ++i) {
var delay = ctx.createDelay(delayDuration);
@ -80,6 +88,9 @@ function onReferenceOutput(e) {
testProcessor = null;
testPanners = null;
// The panning effect is linear so only one reference panner is required.
// This also checks that the individual panners don't chop their output
// too soon.
referencePanner.connect(e.target);
// Assuming the above operations have already scheduled an event to run in
@ -101,16 +112,13 @@ function onReferenceOutput(e) {
e.target.onaudioprocess = null;
e.target.disconnect();
for (var i = 0; i < referenceOutput[0].length; ++i) {
if (referenceOutput[0][i] != 0.0) {
return; // good - a connection must have been received by the graph
}
}
// If the buffer is silent, there is probably not much point just
// increasing the buffer size, because, with the buffer size already
// significantly larger than panner tail time, it demonstrates that the
// lag between threads is much greater than the tail time.
todo(false, "Connections not detected.");
if (isChannelSilent(referenceOutput[0])) {
todo(false, "Connections not detected.");
}
}
referenceProcessCount++;
@ -131,36 +139,30 @@ function onTestOutput(e) {
}
function startTest() {
var ctx = new AudioContext();
// Place the listener to the side of the origin, where the panners are
// positioned, to maximize delay in one ear.
ctx.listener.setPosition(1,0,0);
// 0.002 is MaxDelayTimeSeconds in HRTFpanner.cpp
// and 512 is fftSize() at 48 kHz.
const expectedPannerTailTime = 0.002 * ctx.sampleRate + 512;
// Create some PannerNodes downstream from DelayNodes with delays long
// enough for their source oscillator to finish, dispatch its "ended" event
// enough for their source to finish, dispatch its "ended" event
// and release its playing reference. The DelayNodes should expire their
// tail-time references before the PannerNodes and so only the PannerNode
// lifetimes depends on their tail-time references. Many DelayNodes are
// created and timed to finish at different times so that one PannerNode
// will be finishing the block processed immediately after the connect is
// received.
var oscillator = ctx.createOscillator();
oscillator.start(0);
var source = ctx.createBufferSource();
// Just short of blockSize here to avoid rounding into the next block
oscillator.stop((blockSize - 1) / ctx.sampleRate);
oscillator.onended = function(e) {
var buffer = ctx.createBuffer(1, blockSize - 1, ctx.sampleRate);
for (var i = 0; i < buffer.length; ++i) {
buffer.getChannelData(0)[i] = Math.cos(Math.PI * i / buffer.length);
}
source.buffer = buffer;
source.start(0);
source.onended = function(e) {
gotEnded = true;
};
// The panner effect is linear so only one reference panner is required.
// This also checks that the individual panners don't chop their output too
// soon.
referencePanner = ctx.createPanner();
// Time the first test panner to finish just before downstream DelayNodes
// are about the be connected. Note that DelayNode lifetime depends on
// maxDelayTime so set that equal to the delay.
@ -171,11 +173,11 @@ function startTest() {
for (var i = 0; i < pannerCount; ++i) {
var delay = ctx.createDelay(delayDuration);
delay.delayTime.value = delayDuration;
oscillator.connect(delay);
source.connect(delay);
delay.connect(referencePanner)
var panner = ctx.createPanner();
delay.connect(panner)
delay.connect(panner);
testPanners[i] = panner;
delayDuration += blockSize / ctx.sampleRate;
@ -196,7 +198,33 @@ function startTest() {
testProcessor.connect(ctx.destination);
}
startTest();
function prepareTest() {
ctx = new AudioContext();
// Place the listener to the side of the origin, where the panners are
// positioned, to maximize delay in one ear.
ctx.listener.setPosition(1,0,0);
// A PannerNode will produce no output until it has loaded its HRIR
// database. Wait for this to load before starting the test.
var processor = ctx.createScriptProcessor(bufferSize, 2, 0);
referencePanner = ctx.createPanner();
referencePanner.connect(processor);
var oscillator = ctx.createOscillator();
oscillator.connect(referencePanner);
oscillator.start(0);
processor.onaudioprocess = function(e) {
if (isChannelSilent(e.inputBuffer.getChannelData(0)))
return;
oscillator.stop(0);
oscillator.disconnect();
referencePanner.disconnect();
e.target.onaudioprocess = null;
SimpleTest.executeSoon(startTest);
};
}
prepareTest();
</script>
</pre>
</body>

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

@ -394,7 +394,8 @@ nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
}
nsIDocument* doc = aTargetElement->GetCurrentDoc();
if (doc && !nsStyleUtil::CSPAllowsInlineStyle(doc->NodePrincipal(),
if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
doc->NodePrincipal(),
doc->GetDocumentURI(),
0, aString, nullptr)) {
return;

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

@ -26,8 +26,8 @@ sqlite-version.h: sqlite-version.py sqlite3.h
# We have to preprocess our def file because we need different symbols in debug
# builds exposed that are not built in non-debug builds.
$(DEFFILE): sqlite.def
@$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
$(srcdir)/sqlite.def > $(DEFFILE)
@$(call py_action,preprocessor,$(DEFINES) \
$(srcdir)/sqlite.def -o $(DEFFILE))
export:: sqlite-version.h
endif
@ -118,7 +118,7 @@ include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += -I$(srcdir)
ifeq ($(OS_ARCH),OS2)
ADD_TO_DEF_FILE = $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
ADD_TO_DEF_FILE = $(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) \
$(srcdir)/sqlite.def | sed -e '1,/^EXPORTS$$/ d' -e 's,sqlite3,_\0,' \
-e 's,\ DATA.*$$,,' >> $(DEF_FILE)
endif

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

@ -3620,17 +3620,19 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
if (!(flags & JSRESOLVE_ASSIGNING) && sDocument_id == id) {
nsCOMPtr<nsIDocument> document = win->GetDoc();
JS::Rooted<JS::Value> v(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
&NS_GET_IID(nsIDOMDocument), &v, getter_AddRefs(holder),
false);
NS_ENSURE_SUCCESS(rv, rv);
// nsIDocument::WrapObject will handle defining the property.
*objp = obj;
// NB: We need to do this for any Xray wrapper.
if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
nsCOMPtr<nsIDocument> document = win->GetDoc();
JS::Rooted<JS::Value> v(cx);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
&NS_GET_IID(nsIDOMDocument), &v, getter_AddRefs(holder),
false);
NS_ENSURE_SUCCESS(rv, rv);
*objp = obj;
*_retval = JS_WrapValue(cx, &v) &&
JS_DefineProperty(cx, obj, "document", v,
JS_PropertyStub, JS_StrictPropertyStub,

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

@ -613,6 +613,11 @@ public:
virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::AutoIdVector &props) MOZ_OVERRIDE;
virtual bool watch(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id) MOZ_OVERRIDE;
// Derived traps
virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
@ -962,6 +967,20 @@ nsOuterWindowProxy::AppendIndexedPropertyNames(JSContext *cx, JSObject *proxy,
return true;
}
bool
nsOuterWindowProxy::watch(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, JS::Handle<JSObject*> callable)
{
return js::WatchGuts(cx, proxy, id, callable);
}
bool
nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id)
{
return js::UnwatchGuts(cx, proxy, id);
}
nsOuterWindowProxy
nsOuterWindowProxy::singleton;

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

@ -181,7 +181,7 @@ CheckCSPForEval(JSContext* aCx, nsGlobalWindow* aWindow, ErrorResult& aError)
}
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
fileNameString, scriptSample, lineNum);
fileNameString, scriptSample, lineNum, EmptyString());
}
return allowsEval;

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

@ -235,6 +235,19 @@ BaseDOMProxyHandler::enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
(!proto || js::GetPropertyNames(cx, proto, 0, &props));
}
bool
BaseDOMProxyHandler::watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable)
{
return js::WatchGuts(cx, proxy, id, callable);
}
bool
BaseDOMProxyHandler::unwatch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
{
return js::UnwatchGuts(cx, proxy, id);
}
bool
DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp)
{

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

@ -58,6 +58,11 @@ public:
JS::Handle<jsid> id,
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags) MOZ_OVERRIDE;
bool watch(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JSObject*> callable) MOZ_OVERRIDE;
bool unwatch(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id) MOZ_OVERRIDE;
};
class DOMProxyHandler : public BaseDOMProxyHandler

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

@ -157,14 +157,14 @@ $(test_webidl_files): %: $(srcdir)/test/%
# a symlink, which will clobber files in the srcdir, which is bad.
$(preprocessed_webidl_files): %: $(webidl_base)/% $(GLOBAL_DEPS)
$(RM) $@
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
$(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@
$(call py_action,preprocessor, \
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(webidl_base)/$* -o $@)
# See the comment about PP_TARGETS for $(preprocessed_webidl_files)
$(preprocessed_test_webidl_files): %: $(srcdir)/test/% $(GLOBAL_DEPS)
$(RM) $@
PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
$(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(srcdir)/test/$* -o $@
$(call py_action,preprocessor, \
$(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(srcdir)/test/$* -o $@)
# Make is dumb and can get confused between "foo" and "$(CURDIR)/foo". Make
# sure that the latter depends on the former, since the latter gets used in .pp

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

@ -177,17 +177,17 @@ this.DataStore.prototype = {
getInternalRequest();
},
updateInternal: function(aResolve, aStore, aRevisionStore, aId, aObj) {
debug("UpdateInternal " + aId);
putInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) {
debug("putInternal " + aId);
let self = this;
let request = aStore.put(aObj, aId);
request.onsuccess = function(aEvent) {
debug("UpdateInternal success");
debug("putInternal success");
self.addRevision(aRevisionStore, aId, REVISION_UPDATED,
function() {
debug("UpdateInternal - revisionId increased");
debug("putInternal - revisionId increased");
// No wrap here because the result is always a int.
aResolve(aEvent.target.result);
}
@ -195,11 +195,11 @@ this.DataStore.prototype = {
};
},
addInternal: function(aResolve, aStore, aRevisionStore, aObj) {
addInternal: function(aResolve, aStore, aRevisionStore, aObj, aId) {
debug("AddInternal");
let self = this;
let request = aStore.put(aObj);
let request = aStore.add(aObj, aId);
request.onsuccess = function(aEvent) {
debug("Request successful. Id: " + aEvent.target.result);
self.addRevision(aRevisionStore, aEvent.target.result, REVISION_ADDED,
@ -384,7 +384,7 @@ this.DataStore.prototype = {
);
},
update: function(aId, aObj) {
put: function(aObj, aId) {
aId = parseInt(aId);
if (isNaN(aId) || aId <= 0) {
return throwInvalidArg(this._window);
@ -399,12 +399,19 @@ this.DataStore.prototype = {
// Promise<void>
return this.newDBPromise("readwrite",
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
self.updateInternal(aResolve, aStore, aRevisionStore, aId, aObj);
self.putInternal(aResolve, aStore, aRevisionStore, aObj, aId);
}
);
},
add: function(aObj) {
add: function(aObj, aId) {
if (aId) {
aId = parseInt(aId);
if (isNaN(aId) || aId <= 0) {
return throwInvalidArg(this._window);
}
}
if (this._readOnly) {
return throwReadOnly(this._window);
}
@ -414,7 +421,7 @@ this.DataStore.prototype = {
// Promise<int>
return this.newDBPromise("readwrite",
function(aResolve, aReject, aTxn, aStore, aRevisionStore) {
self.addInternal(aResolve, aStore, aRevisionStore, aObj);
self.addInternal(aResolve, aStore, aRevisionStore, aObj, aId);
}
);
},
@ -458,104 +465,6 @@ this.DataStore.prototype = {
return this._revisionId;
},
getChanges: function(aRevisionId) {
debug("GetChanges: " + aRevisionId);
if (aRevisionId === null || aRevisionId === undefined) {
return this._window.Promise.reject(
new this._window.DOMError("SyntaxError", "Invalid revisionId"));
}
let self = this;
// Promise<DataStoreChanges>
return new this._window.Promise(function(aResolve, aReject) {
debug("GetChanges promise started");
self._db.revisionTxn(
'readonly',
function(aTxn, aStore) {
debug("GetChanges transaction success");
let request = self._db.getInternalRevisionId(
aRevisionId,
aStore,
function(aInternalRevisionId) {
if (aInternalRevisionId == undefined) {
aResolve(undefined);
return;
}
// This object is the return value of this promise.
// Initially we use maps, and then we convert them in array.
let changes = {
revisionId: '',
addedIds: {},
updatedIds: {},
removedIds: {}
};
let request = aStore.mozGetAll(IDBKeyRange.lowerBound(aInternalRevisionId, true));
request.onsuccess = function(aEvent) {
for (let i = 0; i < aEvent.target.result.length; ++i) {
let data = aEvent.target.result[i];
switch (data.operation) {
case REVISION_ADDED:
changes.addedIds[data.objectId] = true;
break;
case REVISION_UPDATED:
// We don't consider an update if this object has been added
// or if it has been already modified by a previous
// operation.
if (!(data.objectId in changes.addedIds) &&
!(data.objectId in changes.updatedIds)) {
changes.updatedIds[data.objectId] = true;
}
break;
case REVISION_REMOVED:
let id = data.objectId;
// If the object has been added in this range of revisions
// we can ignore it and remove it from the list.
if (id in changes.addedIds) {
delete changes.addedIds[id];
} else {
changes.removedIds[id] = true;
}
if (id in changes.updatedIds) {
delete changes.updatedIds[id];
}
break;
}
}
// The last revisionId.
if (aEvent.target.result.length) {
changes.revisionId = aEvent.target.result[aEvent.target.result.length - 1].revisionId;
}
// From maps to arrays.
changes.addedIds = Object.keys(changes.addedIds).map(function(aKey) { return parseInt(aKey, 10); });
changes.updatedIds = Object.keys(changes.updatedIds).map(function(aKey) { return parseInt(aKey, 10); });
changes.removedIds = Object.keys(changes.removedIds).map(function(aKey) { return parseInt(aKey, 10); });
let wrappedObject = ObjectWrapper.wrap(changes, self._window);
aResolve(wrappedObject);
};
}
);
},
function(aEvent) {
debug("GetChanges transaction failed");
aReject(createDOMError(self._window, aEvent));
}
);
});
},
getLength: function() {
let self = this;

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

@ -83,10 +83,10 @@ DataStoreDB.prototype = {
);
},
addRevision: function(aStore, aId, aType, aSuccessCb) {
debug("AddRevision: " + aId + " - " + aType);
addRevision: function(aStore, aKey, aType, aSuccessCb) {
debug("AddRevision: " + aKey + " - " + aType);
let revisionId = uuidgen.generateUUID().toString();
let request = aStore.put({ revisionId: revisionId, objectId: aId, operation: aType });
let request = aStore.put({ revisionId: revisionId, objectId: aKey, operation: aType });
request.onsuccess = function() {
aSuccessCb(revisionId);
}

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

@ -34,7 +34,7 @@
var store = stores[0];
ok("get" in store, "store.get exists");
ok("update" in store, "store.update exists");
ok("put" in store, "store.put exists");
ok("add" in store, "store.add exists");
ok("remove" in store, "store.remove exists");
ok("clear" in store, "store.clear exists");

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

@ -34,12 +34,11 @@
var store = stores[0];
ok("get" in store, "store.get exists");
ok("update" in store, "store.update exists");
ok("put" in store, "store.put exists");
ok("add" in store, "store.add exists");
ok("remove" in store, "store.remove exists");
ok("clear" in store, "store.clear exists");
ok("revisionId" in store, "store.revisionId exists");
ok("getChanges" in store, "store.getChanges exists");
ok("getLength" in store, "store.getLength exists");
ok("sync" in store, "store.sync exists");
@ -66,9 +65,9 @@
}, cbError);
}
function testStoreUpdate(id, value) {
return gStore.update(id, value).then(function() {
ok(true, "store.update() is called");
function testStorePut(value, id) {
return gStore.put(value, id).then(function() {
ok(true, "store.put() is called");
}, cbError);
}
@ -114,8 +113,8 @@
gId = id; runTest(); }, cbError); },
function() { testStoreGet(gId, "hello world"); },
// Update + Get - string
function() { testStoreUpdate(gId, "hello world 2").then(function() {
// Put + Get - string
function() { testStorePut("hello world 2", gId).then(function() {
runTest(); }, cbError); },
function() { testStoreGet(gId, "hello world 2"); },

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

@ -49,9 +49,9 @@
}, cbError);
}
function testStoreUpdate(id, value) {
gStore.update(id, value).then(function(retId) {
is(id, retId, "store.update() is called with the right id");
function testStorePut(value, id) {
gStore.put(value, id).then(function(retId) {
is(id, retId, "store.put() is called with the right id");
}, cbError);
}
@ -84,9 +84,9 @@
function() { gChangeId = 1; gChangeOperation = 'added';
testStoreAdd({ number: 42 }, 1); },
// Update
// Put
function() { gChangeId = 1; gChangeOperation = 'updated';
testStoreUpdate(1, { number: 43 }); },
testStorePut({ number: 43 }, 1); },
// Remove
function() { gChangeId = 1; gChangeOperation = 'removed';
@ -103,9 +103,9 @@
function() { gChangeId = 2; gChangeOperation = 'added';
testStoreAdd({ number: 42 }, 2); },
// Update
// Put
function() { gChangeId = 2; gChangeOperation = 'updated';
testStoreUpdate(2, { number: 43 }); },
testStorePut({ number: 43 }, 2); },
// Remove
function() { gChangeId = 2; gChangeOperation = 'removed';

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

@ -33,7 +33,7 @@
var store = stores[0];
ok("get" in store, "store.get exists");
ok("update" in store, "store.update exists");
ok("put" in store, "store.put exists");
ok("add" in store, "store.add exists");
ok("remove" in store, "store.remove exists");
ok("clear" in store, "store.clear exists");
@ -51,11 +51,11 @@
f = f.then(cbError, function() {
ok(true, "store.add() fails because the db is readonly");
return store.update(123, {});
return store.put({}, 123);
})
f = f.then(cbError, function() {
ok(true, "store.update() fails because the db is readonly");
ok(true, "store.put() fails because the db is readonly");
})
f.then(function() {

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

@ -1,196 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
var gStore;
var gPreviousRevisionId = '';
function is(a, b, msg) {
alert((a === b ? 'OK' : 'KO') + ' ' + msg)
}
function isnot(a, b, msg) {
alert((a !== b ? 'OK' : 'KO') + ' ' + msg)
}
function ok(a, msg) {
alert((a ? 'OK' : 'KO')+ ' ' + msg)
}
function cbError() {
alert('KO error');
}
function finish() {
alert('DONE');
}
function testGetDataStores() {
navigator.getDataStores('foo').then(function(stores) {
is(stores.length, 1, "getDataStores('foo') returns 1 element");
is(stores[0].name, 'foo', 'The dataStore.name is foo');
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
gStore = stores[0];
runTest();
}, cbError);
}
function testStoreAdd(value, expectedId) {
return gStore.add(value).then(function(id) {
is(id, expectedId, "store.add() is called");
runTest();
}, cbError);
}
function testStoreUpdate(id, value) {
return gStore.update(id, value).then(function(retId) {
is(id, retId, "store.update() is called with the right id");
runTest();
}, cbError);
}
function testStoreRemove(id, expectedSuccess) {
return gStore.remove(id).then(function(success) {
is(success, expectedSuccess, "store.remove() returns the right value");
runTest();
}, cbError);
}
function testStoreRevisionId() {
is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(gStore.revisionId), true, "store.revisionId returns something");
runTest();
}
function testStoreWrongRevisions(id) {
return gStore.getChanges(id).then(
function(what) {
is(what, undefined, "Wrong revisionId == undefined object");
runTest();
}, cbError);
}
function testStoreRevisions(id, changes) {
return gStore.getChanges(id).then(function(what) {
is(JSON.stringify(changes.addedIds),
JSON.stringify(what.addedIds), "store.revisions - addedIds: " +
JSON.stringify(what.addedIds) + " | " + JSON.stringify(changes.addedIds));
is(JSON.stringify(changes.updatedIds),
JSON.stringify(what.updatedIds), "store.revisions - updatedIds: " +
JSON.stringify(what.updatedIds) + " | " + JSON.stringify(changes.updatedIds));
is(JSON.stringify(changes.removedIds),
JSON.stringify(what.removedIds), "store.revisions - removedIds: " +
JSON.stringify(what.removedIds) + " | " + JSON.stringify(changes.removedIds));
runTest();
}, cbError);
}
function testStoreRevisionIdChanged() {
isnot(gStore.revisionId, gPreviousRevisionId, "Revision changed");
gPreviousRevisionId = gStore.revisionId;
runTest();
}
function testStoreRevisionIdNotChanged() {
is(gStore.revisionId, gPreviousRevisionId, "Revision changed");
runTest();
}
var revisions = [];
var tests = [
// Test for GetDataStore
testGetDataStores,
// The first revision is not empty
testStoreRevisionIdChanged,
// wrong revision ID
function() { testStoreWrongRevisions('foobar'); },
// Add
function() { testStoreAdd({ number: 42 }, 1); },
function() { revisions.push(gStore.revisionId); testStoreRevisionId(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [], updatedIds: [], removedIds: [] }); },
// Add
function() { testStoreAdd({ number: 42 }, 2); },
function() { revisions.push(gStore.revisionId); runTest(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [2], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[1], { addedIds: [], updatedIds: [], removedIds: [] }); },
// Add
function() { testStoreAdd({ number: 42 }, 3); },
function() { revisions.push(gStore.revisionId); runTest(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [2,3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[1], { addedIds: [3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[2], { addedIds: [], updatedIds: [], removedIds: [] }); },
// Update
function() { testStoreUpdate(3, { number: 43 }); },
function() { revisions.push(gStore.revisionId); runTest(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [2,3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[1], { addedIds: [3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[2], { addedIds: [], updatedIds: [3], removedIds: [] }); },
function() { testStoreRevisions(revisions[3], { addedIds: [], updatedIds: [], removedIds: [] }); },
// Update
function() { testStoreUpdate(3, { number: 42 }); },
function() { revisions.push(gStore.revisionId); runTest(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [2,3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[1], { addedIds: [3], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[2], { addedIds: [], updatedIds: [3], removedIds: [] }); },
function() { testStoreRevisions(revisions[3], { addedIds: [], updatedIds: [3], removedIds: [] }); },
function() { testStoreRevisions(revisions[4], { addedIds: [], updatedIds: [], removedIds: [] }); },
// Remove
function() { testStoreRemove(3, true); },
function() { revisions.push(gStore.revisionId); runTest(); },
testStoreRevisionIdChanged,
function() { testStoreRevisions(revisions[0], { addedIds: [2], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[1], { addedIds: [], updatedIds: [], removedIds: [] }); },
function() { testStoreRevisions(revisions[2], { addedIds: [], updatedIds: [], removedIds: [3] }); },
function() { testStoreRevisions(revisions[3], { addedIds: [], updatedIds: [], removedIds: [3] }); },
function() { testStoreRevisions(revisions[4], { addedIds: [], updatedIds: [], removedIds: [3] }); },
function() { testStoreRevisions(revisions[5], { addedIds: [], updatedIds: [], removedIds: [] }); },
function() { testStoreRemove(3, false); },
testStoreRevisionIdNotChanged,
// Remove
function() { testStoreRemove(42, false); },
testStoreRevisionIdNotChanged,
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
runTest();
</script>
</pre>
</body>
</html>

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

@ -133,14 +133,14 @@
function() {
gExpectedEvents = true;
gStore.add(1).then(function(id) {
gStore.add(1,2).then(function(id) {
gRevisions.push(gStore.revisionId);
ok(true, "Iteme: " + id + " added");
});
},
function() {
gStore.add(2).then(function(id) {
gStore.add(2,3).then(function(id) {
gRevisions.push(gStore.revisionId);
ok(true, "Iteme: " + id + " added");
});
@ -150,8 +150,8 @@
gExpectedEvents = false;
var cursor = gStore.sync();
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 1 },
{ operation: 'add', id: 2, data: 2 },
{ operation: 'add', id: 2, data: 1 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -159,23 +159,23 @@
function() {
var cursor = gStore.sync('wrong revision ID');
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 1 },
{ operation: 'add', id: 2, data: 2 },
{ operation: 'add', id: 2, data: 1 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[0]);
var steps = [ { operation: 'add', id: 1, data: 1 },
{ operation: 'add', id: 2, data: 2 },
var steps = [ { operation: 'add', id: 2, data: 1 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[1]);
var steps = [ { operation: 'add', id: 2, data: 2 },
var steps = [ { operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -189,7 +189,7 @@
// Test after an update
function() {
gExpectedEvents = true;
gStore.update(1, 3).then(function() {
gStore.put(3, 2).then(function() {
gRevisions.push(gStore.revisionId);
});
},
@ -198,8 +198,8 @@
gExpectedEvents = false;
var cursor = gStore.sync();
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 3 },
{ operation: 'add', id: 2, data: 2 },
{ operation: 'add', id: 2, data: 3 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -207,31 +207,31 @@
function() {
var cursor = gStore.sync('wrong revision ID');
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 3 },
{ operation: 'add', id: 2, data: 2 },
{ operation: 'add', id: 2, data: 3 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[0]);
var steps = [ { operation: 'add', id: 1, data: 3 },
{ operation: 'add', id: 2, data: 2 },
var steps = [ { operation: 'add', id: 2, data: 3 },
{ operation: 'add', id: 3, data: 2 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[1]);
var steps = [ { operation: 'add', id: 2, data: 2 },
{ operation: 'update', id: 1, data: 3 },
var steps = [ { operation: 'add', id: 3, data: 2 },
{ operation: 'update', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[2]);
var steps = [ { operation: 'update', id: 1, data: 3 },
var steps = [ { operation: 'update', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -245,7 +245,7 @@
// Test after a remove
function() {
gExpectedEvents = true;
gStore.remove(2).then(function() {
gStore.remove(3).then(function() {
gRevisions.push(gStore.revisionId);
});
},
@ -254,7 +254,7 @@
gExpectedEvents = false;
var cursor = gStore.sync();
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 3 },
{ operation: 'add', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -262,36 +262,36 @@
function() {
var cursor = gStore.sync('wrong revision ID');
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 3 },
{ operation: 'add', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[0]);
var steps = [ { operation: 'add', id: 1, data: 3 },
var steps = [ { operation: 'add', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[1]);
var steps = [ { operation: 'update', id: 1, data: 3 },
var steps = [ { operation: 'update', id: 2, data: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[2]);
var steps = [ { operation: 'update', id: 1, data: 3 },
{ operation: 'remove', id: 2 },
var steps = [ { operation: 'update', id: 2, data: 3 },
{ operation: 'remove', id: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
function() {
var cursor = gStore.sync(gRevisions[3]);
var steps = [ { operation: 'remove', id: 2 },
var steps = [ { operation: 'remove', id: 3 },
{ operation: 'done' }];
testCursor(cursor, steps);
},
@ -306,7 +306,7 @@
function() {
gCursor = gStore.sync();
var steps = [ { operation: 'clear', },
{ operation: 'add', id: 1, data: 3 } ];
{ operation: 'add', id: 2, data: 3 } ];
testCursor(gCursor, steps);
},
@ -320,31 +320,31 @@
// New events when the cursor is active
function() {
var steps = [ { operation: 'add', id: 3, data: 42 } ];
var steps = [ { operation: 'add', id: 4, data: 42 } ];
testCursor(gCursor, steps);
},
function() {
gStore.update(1, 42).then(function(id) {
gStore.put(42, 2).then(function(id) {
gRevisions.push(gStore.revisionId);
runTest();
});
},
function() {
var steps = [ { operation: 'update', id: 1, data: 42 } ];
var steps = [ { operation: 'update', id: 2, data: 42 } ];
testCursor(gCursor, steps);
},
function() {
gStore.remove(1).then(function(id) {
gStore.remove(2).then(function(id) {
gRevisions.push(gStore.revisionId);
runTest();
});
},
function() {
var steps = [ { operation: 'remove', id: 1 } ];
var steps = [ { operation: 'remove', id: 2 } ];
testCursor(gCursor, steps);
},
@ -357,7 +357,7 @@
},
function() {
var steps = [ { operation: 'add', id: 4, data: 42 } ];
var steps = [ { operation: 'add', id: 5, data: 42 } ];
testCursor(gCursor, steps);
},
@ -378,7 +378,7 @@
function() {
var steps = [ { operation: 'clear' },
{ operation: 'add', id: 5, data: 42 },
{ operation: 'add', id: 6, data: 42 },
{ operation: 'done' } ];
testCursor(gCursor, steps);
},

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

@ -3,7 +3,6 @@ support-files =
file_app_install.html
file_readonly.html
file_basic.html
file_revision.html
file_changes.html
file_changes2.html
file_app.sjs
@ -16,7 +15,6 @@ support-files =
[test_app_install.html]
[test_readonly.html]
[test_basic.html]
[test_revision.html]
[test_changes.html]
[test_arrays.html]
[test_oop.html]

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

@ -1,140 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
var gBaseURL = 'http://test/tests/dom/datastore/tests/';
var gHostedManifestURL = gBaseURL + 'file_app.sjs?testToken=file_revision.html';
var gApp;
var gStore;
var gPreviousRevisionId = '';
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
runTest();
}
}
function uninstallApp() {
// Uninstall the app.
var request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
ok(true, "All done");
runTest();
}
}
function testApp() {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('content');
// Set us up to listen for messages from the app.
var listener = function(e) {
var message = e.detail.message;
if (/^OK/.exec(message)) {
ok(true, "Message from app: " + message);
} else if (/KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
runTest();
}
}
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
domParent.appendChild(ifr);
}
var revisions = [];
var tests = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
},
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, runTest);
},
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true]]}, runTest);
},
// Enabling mozBrowser
function() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true]]}, runTest);
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(runTest);
},
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
function finish() {
SimpleTest.finish();
}
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</pre>
</body>
</html>

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

@ -179,7 +179,8 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
NS_ConvertUTF8toUTF16(asciiSpec),
NS_ConvertUTF8toUTF16(mURL),
0);
0,
EmptyString());
}
//return early if inline scripts are not allowed

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

@ -24,10 +24,10 @@ interface DataStore : EventTarget {
Promise get(sequence<unsigned long> id);
// Promise<void>
Promise update(unsigned long id, any obj);
Promise put(any obj, unsigned long id);
// Promise<unsigned long>
Promise add(any obj);
Promise add(any obj, optional unsigned long id);
// Promise<boolean>
Promise remove(unsigned long id);
@ -39,22 +39,12 @@ interface DataStore : EventTarget {
attribute EventHandler onchange;
// Promise<DataStoreChanges>
Promise getChanges(DOMString revisionId);
// Promise<unsigned long>
Promise getLength();
DataStoreCursor sync(optional DOMString revisionId = "");
};
dictionary DataStoreChanges {
DOMString revisionId;
sequence<unsigned long> addedIds;
sequence<unsigned long> updatedIds;
sequence<unsigned long> removedIds;
};
[Pref="dom.datastore.enabled",
JSImplementation="@mozilla.org/dom/datastore-cursor;1"]
interface DataStoreCursor {

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

@ -28,7 +28,7 @@ typedef any Transferable;
// the current browsing context
[Unforgeable, Throws] readonly attribute WindowProxy window;
[Replaceable, Throws] readonly attribute WindowProxy self;
[Unforgeable] readonly attribute Document? document;
//[Unforgeable] readonly attribute Document? document;
[Throws] attribute DOMString name;
[PutForwards=href, Unforgeable, Throws] readonly attribute Location? location;
[Throws] readonly attribute History history;

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

@ -707,7 +707,7 @@ public:
"Call to eval() or related function blocked by CSP.");
if (mWorkerPrivate->GetReportCSPViolations()) {
csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
mFileName, scriptSample, mLineNum);
mFileName, scriptSample, mLineNum, EmptyString());
}
}

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

@ -68,6 +68,8 @@ enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
#ifdef HAVE_CPUID_H
#if !(defined(__SSE2__) || defined(_M_X64) || \
(defined(_M_IX86_FP) && _M_IX86_FP >= 2))
// cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
#include <cpuid.h>
@ -78,6 +80,7 @@ HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
(regs[reg] & bit);
}
#endif
#define HAVE_CPU_DETECTION
#else

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

@ -738,6 +738,8 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
mDTBuffer->ReleaseBits(data);
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
EnsureBufferOnWhite();
MOZ_ASSERT(mDTBufferOnWhite);
mDTBufferOnWhite->LockBits(&data, &size, &stride, &format);
uint8_t bytesPerPixel = BytesPerPixel(format);
BufferUnrotate(data,
@ -834,7 +836,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
NS_ASSERTION(destDTBufferOnWhite, "Must have a white buffer!");
destDTBufferOnWhite->SetTransform(mat);
EnsureBufferOnWhite();
MOZ_ASSERT(destDTBufferOnWhite, "Have we got a Thebes buffer for some reason?");
MOZ_ASSERT(mDTBufferOnWhite, "Have we got a Thebes buffer for some reason?");
DrawBufferWithRotation(destDTBufferOnWhite, BUFFER_WHITE, 1.0, OP_SOURCE);
destDTBufferOnWhite->SetTransform(Matrix());
}

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

@ -231,7 +231,8 @@ ApplyTransform(nsIntPoint* aPoint, const gfx3DMatrix& aMatrix)
}
nsEventStatus
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
APZCTreeManager::ReceiveInputEvent(const InputData& aEvent,
ScrollableLayerGuid* aOutTargetGuid)
{
nsEventStatus result = nsEventStatus_eIgnore;
gfx3DMatrix transformToApzc;
@ -261,6 +262,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
APZC_LOG("Re-using APZC %p as continuation of event block\n", mApzcForInputBlock.get());
}
if (mApzcForInputBlock) {
mApzcForInputBlock->GetGuid(aOutTargetGuid);
// Use the cached transform to compute the point to send to the APZC.
// This ensures that the sequence of touch points an APZC sees in an
// input block are all in the same coordinate space.
@ -290,6 +292,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
const PinchGestureInput& pinchInput = aEvent.AsPinchGestureInput();
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(pinchInput.mFocusPoint);
if (apzc) {
apzc->GetGuid(aOutTargetGuid);
GetInputTransforms(apzc, transformToApzc, transformToGecko);
PinchGestureInput inputForApzc(pinchInput);
ApplyTransform(&(inputForApzc.mFocusPoint), transformToApzc);
@ -300,6 +303,7 @@ APZCTreeManager::ReceiveInputEvent(const InputData& aEvent)
const TapGestureInput& tapInput = aEvent.AsTapGestureInput();
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(tapInput.mPoint));
if (apzc) {
apzc->GetGuid(aOutTargetGuid);
GetInputTransforms(apzc, transformToApzc, transformToGecko);
TapGestureInput inputForApzc(tapInput);
ApplyTransform(&(inputForApzc.mPoint), transformToApzc);
@ -342,6 +346,7 @@ APZCTreeManager::GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent,
nsEventStatus
APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetTouchEvent* aOutEvent)
{
nsEventStatus ret = nsEventStatus_eIgnore;
@ -355,6 +360,7 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
}
if (mApzcForInputBlock) {
mApzcForInputBlock->GetGuid(aOutTargetGuid);
// For computing the input for the APZC, used the cached transform.
// This ensures that the sequence of touch points an APZC sees in an
// input block are all in the same coordinate space.
@ -392,14 +398,34 @@ APZCTreeManager::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
return ret;
}
void
APZCTreeManager::TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
LayoutDeviceIntPoint* aOutTransformedPoint)
{
MOZ_ASSERT(aOutTransformedPoint);
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aPoint);
if (apzc && aOutTransformedPoint) {
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToGecko;
GetInputTransforms(apzc, transformToApzc, transformToGecko);
gfx3DMatrix outTransform = transformToApzc * transformToGecko;
aOutTransformedPoint->x = aPoint.x;
aOutTransformedPoint->y = aPoint.y;
ApplyTransform(aOutTransformedPoint, outTransform);
}
}
nsEventStatus
APZCTreeManager::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetMouseEvent* aOutEvent)
{
nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y));
if (!apzc) {
return nsEventStatus_eIgnore;
}
apzc->GetGuid(aOutTargetGuid);
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToGecko;
GetInputTransforms(apzc, transformToApzc, transformToGecko);
@ -412,6 +438,7 @@ APZCTreeManager::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
nsEventStatus
APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetInputEvent* aOutEvent)
{
// Transform the refPoint
@ -419,6 +446,7 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
if (!apzc) {
return nsEventStatus_eIgnore;
}
apzc->GetGuid(aOutTargetGuid);
gfx3DMatrix transformToApzc;
gfx3DMatrix transformToGecko;
GetInputTransforms(apzc, transformToApzc, transformToGecko);
@ -429,6 +457,7 @@ APZCTreeManager::ProcessEvent(const WidgetInputEvent& aEvent,
nsEventStatus
APZCTreeManager::ReceiveInputEvent(const WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetInputEvent* aOutEvent)
{
MOZ_ASSERT(NS_IsMainThread());
@ -436,32 +465,33 @@ APZCTreeManager::ReceiveInputEvent(const WidgetInputEvent& aEvent,
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
const WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
return ProcessTouchEvent(touchEvent, aOutEvent->AsTouchEvent());
return ProcessTouchEvent(touchEvent, aOutTargetGuid, aOutEvent->AsTouchEvent());
}
case NS_MOUSE_EVENT: {
// For b2g emulation
const WidgetMouseEvent& mouseEvent = *aEvent.AsMouseEvent();
WidgetMouseEvent* outMouseEvent = aOutEvent->AsMouseEvent();
return ProcessMouseEvent(mouseEvent, outMouseEvent);
return ProcessMouseEvent(mouseEvent, aOutTargetGuid, outMouseEvent);
}
default: {
return ProcessEvent(aEvent, aOutEvent);
return ProcessEvent(aEvent, aOutTargetGuid, aOutEvent);
}
}
}
nsEventStatus
APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent)
APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid)
{
MOZ_ASSERT(NS_IsMainThread());
switch (aEvent.eventStructType) {
case NS_TOUCH_EVENT: {
WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
return ProcessTouchEvent(touchEvent, &touchEvent);
return ProcessTouchEvent(touchEvent, aOutTargetGuid, &touchEvent);
}
default: {
return ProcessEvent(aEvent, &aEvent);
return ProcessEvent(aEvent, aOutTargetGuid, &aEvent);
}
}
}
@ -567,7 +597,7 @@ APZCTreeManager::HandleOverscroll(AsyncPanZoomController* aChild, ScreenPoint aS
}
bool
APZCTreeManager::HitTestAPZC(const ScreenPoint& aPoint)
APZCTreeManager::HitTestAPZC(const ScreenIntPoint& aPoint)
{
MonitorAutoLock lock(mTreeLock);
nsRefPtr<AsyncPanZoomController> target;

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

@ -44,6 +44,14 @@ struct ScrollableLayerGuid {
uint32_t mPresShellId;
FrameMetrics::ViewID mScrollId;
ScrollableLayerGuid()
: mLayersId(0)
, mPresShellId(0)
, mScrollId(0)
{
MOZ_COUNT_CTOR(ScrollableLayerGuid);
}
ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
FrameMetrics::ViewID aScrollId)
: mLayersId(aLayersId)
@ -142,8 +150,13 @@ public:
* General handler for incoming input events. Manipulates the frame metrics
* based on what type of input it is. For example, a PinchGestureEvent will
* cause scaling. This should only be called externally to this class.
*
* @param aEvent input event object, will not be modified
* @param aOutTargetGuid returns the guid of the apzc this event was
* delivered to. May be null.
*/
nsEventStatus ReceiveInputEvent(const InputData& aEvent);
nsEventStatus ReceiveInputEvent(const InputData& aEvent,
ScrollableLayerGuid* aOutTargetGuid);
/**
* WidgetInputEvent handler. Sets |aOutEvent| (which is assumed to be an
@ -158,9 +171,12 @@ public:
* to the appropriate apz as such.
*
* @param aEvent input event object, will not be modified
* @param aOutTargetGuid returns the guid of the apzc this event was
* delivered to. May be null.
* @param aOutEvent event object transformed to DOM coordinate space.
*/
nsEventStatus ReceiveInputEvent(const WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
WidgetInputEvent* aOutEvent);
/**
@ -168,8 +184,20 @@ public:
* WidgetInputEvent. Must be called on the main thread.
*
* @param aEvent input event object
* @param aOutTargetGuid returns the guid of the apzc this event was
* delivered to. May be null.
*/
nsEventStatus ReceiveInputEvent(WidgetInputEvent& aEvent);
nsEventStatus ReceiveInputEvent(WidgetInputEvent& aEvent,
ScrollableLayerGuid* aOutTargetGuid);
/**
* A helper for transforming coordinates to gecko coordinate space.
*
* @param aPoint point to transform
* @param aOutTransformedPoint resulting transformed point
*/
void TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
LayoutDeviceIntPoint* aOutTransformedPoint);
/**
* Updates the composition bounds, i.e. the dimensions of the final size of
@ -235,7 +263,7 @@ public:
/**
* Tests if a screen point intersect an apz in the tree.
*/
bool HitTestAPZC(const ScreenPoint& aPoint);
bool HitTestAPZC(const ScreenIntPoint& aPoint);
/**
* Set the dpi value used by all AsyncPanZoomControllers.
@ -285,9 +313,9 @@ private:
AsyncPanZoomController* CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
AsyncPanZoomController* RootAPZCForLayersId(AsyncPanZoomController* aApzc);
AsyncPanZoomController* GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, WidgetTouchEvent* aOutEvent);
nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, WidgetMouseEvent* aOutEvent);
nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, WidgetInputEvent* aOutEvent);
nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* aOutEvent);
/**
* Recursive helper function to build the APZC tree. The tree of APZC instances has

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

@ -1544,5 +1544,15 @@ bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
return aGuid.mLayersId == mLayersId && aGuid.mScrollId == mFrameMetrics.mScrollId;
}
void AsyncPanZoomController::GetGuid(ScrollableLayerGuid* aGuidOut)
{
if (!aGuidOut) {
return;
}
aGuidOut->mLayersId = mLayersId;
aGuidOut->mScrollId = mFrameMetrics.mScrollId;
aGuidOut->mPresShellId = mFrameMetrics.mPresShellId;
}
}
}

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

@ -231,6 +231,11 @@ public:
*/
nsEventStatus HandleInputEvent(const InputData& aEvent);
/**
* Populates the provided object with the scrollable guid of this apzc.
*/
void GetGuid(ScrollableLayerGuid* aGuidOut);
/**
* Returns true if this APZC instance is for the layer identified by the guid.
*/

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

@ -113,6 +113,25 @@ void ApzcPan(AsyncPanZoomController* apzc, int& aTime, int aTouchStartY, int aTo
status = apzc->HandleInputEvent(mti);
}
static void
ApzcPinch(AsyncPanZoomController* aApzc, int aFocusX, int aFocusY, float aScale) {
aApzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
0,
ScreenPoint(aFocusX, aFocusY),
10.0,
10.0));
aApzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
0,
ScreenPoint(aFocusX, aFocusY),
10.0 * aScale,
10.0));
aApzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
0,
ScreenPoint(aFocusX, aFocusY),
10.0 * aScale,
10.0 * aScale));
}
TEST(AsyncPanZoomController, Constructor) {
// RefCounted class can't live in the stack
nsRefPtr<MockContentController> mcc = new MockContentController();
@ -136,21 +155,7 @@ TEST(AsyncPanZoomController, Pinch) {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
0,
ScreenPoint(250, 300),
10.0,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
0,
ScreenPoint(250, 300),
12.5,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
0,
ScreenPoint(250, 300),
12.5,
12.5));
ApzcPinch(apzc, 250, 300, 1.25);
// the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
fm = apzc->GetFrameMetrics();
@ -165,21 +170,7 @@ TEST(AsyncPanZoomController, Pinch) {
apzc->SetFrameMetrics(fm);
// the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
0,
ScreenPoint(250, 300),
10.0,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
0,
ScreenPoint(250, 300),
5.0,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
0,
ScreenPoint(250, 300),
5.0,
5.0));
ApzcPinch(apzc, 250, 300, 0.5);
// the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
fm = apzc->GetFrameMetrics();
@ -204,26 +195,14 @@ TEST(AsyncPanZoomController, Overzoom) {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(1);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
0,
ScreenPoint(50, 50),
10.0,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
0,
ScreenPoint(50, 50),
5.0,
10.0));
apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
0,
ScreenPoint(50, 50),
5.0,
5.0));
ApzcPinch(apzc, 50, 50, 0.5);
fm = apzc->GetFrameMetrics();
EXPECT_EQ(fm.mZoom.scale, 0.8f);
EXPECT_EQ(fm.mScrollOffset.x, 0);
EXPECT_EQ(fm.mScrollOffset.y, 0);
// bug 936721 - PGO builds introduce rounding error so
// use a fuzzy match instead
EXPECT_LT(abs(fm.mScrollOffset.x), 1e-5);
EXPECT_LT(abs(fm.mScrollOffset.y), 1e-5);
}
TEST(AsyncPanZoomController, SimpleTransform) {

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

@ -7,7 +7,6 @@
DIRS += [
'idl',
'public',
'util',
'ucvja',
'ucvcn',
'ucvlatin',

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

@ -13,16 +13,6 @@ LOCAL_INCLUDES = -I$(srcdir)/../util \
-I$(srcdir)/../ucvcn \
$(NULL)
SHARED_LIBRARY_LIBS += \
../ucvlatin/$(LIB_PREFIX)ucvlatin_s.$(LIB_SUFFIX) \
../ucvibm/$(LIB_PREFIX)ucvibm_s.$(LIB_SUFFIX) \
../ucvja/$(LIB_PREFIX)ucvja_s.$(LIB_SUFFIX) \
../ucvtw2/$(LIB_PREFIX)ucvtw2_s.$(LIB_SUFFIX) \
../ucvtw/$(LIB_PREFIX)ucvtw_s.$(LIB_SUFFIX) \
../ucvko/$(LIB_PREFIX)ucvko_s.$(LIB_SUFFIX) \
../ucvcn/$(LIB_PREFIX)ucvcn_s.$(LIB_SUFFIX) \
$(NULL)
include $(topsrcdir)/config/rules.mk
ifneq (,$(INTEL_ARCHITECTURE))

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

@ -24,6 +24,197 @@ UNIFIED_SOURCES += [
'nsUTF8ToUnicode.cpp',
]
UNIFIED_SOURCES += [
'../ucvcn/nsGBKConvUtil.cpp',
'../ucvcn/nsGBKToUnicode.cpp',
'../ucvcn/nsHZToUnicode.cpp',
'../ucvcn/nsISO2022CNToUnicode.cpp',
'../ucvcn/nsUnicodeToGB2312V2.cpp',
'../ucvcn/nsUnicodeToGBK.cpp',
'../ucvcn/nsUnicodeToHZ.cpp',
]
UNIFIED_SOURCES += [
'../ucvibm/nsCP850ToUnicode.cpp',
'../ucvibm/nsCP852ToUnicode.cpp',
'../ucvibm/nsCP855ToUnicode.cpp',
'../ucvibm/nsCP857ToUnicode.cpp',
'../ucvibm/nsCP862ToUnicode.cpp',
'../ucvibm/nsCP864ToUnicode.cpp',
'../ucvibm/nsUnicodeToCP850.cpp',
'../ucvibm/nsUnicodeToCP852.cpp',
'../ucvibm/nsUnicodeToCP855.cpp',
'../ucvibm/nsUnicodeToCP857.cpp',
'../ucvibm/nsUnicodeToCP862.cpp',
'../ucvibm/nsUnicodeToCP864.cpp',
]
UNIFIED_SOURCES += [
'../ucvja/nsJapaneseToUnicode.cpp',
'../ucvja/nsUnicodeToEUCJP.cpp',
'../ucvja/nsUnicodeToISO2022JP.cpp',
'../ucvja/nsUnicodeToJISx0201.cpp',
'../ucvja/nsUnicodeToSJIS.cpp',
]
UNIFIED_SOURCES += [
'../ucvko/nsCP949ToUnicode.cpp',
'../ucvko/nsISO2022KRToUnicode.cpp',
'../ucvko/nsJohabToUnicode.cpp',
'../ucvko/nsUnicodeToCP949.cpp',
'../ucvko/nsUnicodeToJohab.cpp',
]
UNIFIED_SOURCES += [
'../ucvlatin/nsARMSCII8ToUnicode.cpp',
'../ucvlatin/nsAsciiToUnicode.cpp',
'../ucvlatin/nsCP1250ToUnicode.cpp',
'../ucvlatin/nsCP1251ToUnicode.cpp',
'../ucvlatin/nsCP1253ToUnicode.cpp',
'../ucvlatin/nsCP1254ToUnicode.cpp',
'../ucvlatin/nsCP1255ToUnicode.cpp',
'../ucvlatin/nsCP1256ToUnicode.cpp',
'../ucvlatin/nsCP1257ToUnicode.cpp',
'../ucvlatin/nsCP1258ToUnicode.cpp',
'../ucvlatin/nsCP866ToUnicode.cpp',
'../ucvlatin/nsCP874ToUnicode.cpp',
'../ucvlatin/nsISO885910ToUnicode.cpp',
'../ucvlatin/nsISO885911ToUnicode.cpp',
'../ucvlatin/nsISO885913ToUnicode.cpp',
'../ucvlatin/nsISO885914ToUnicode.cpp',
'../ucvlatin/nsISO885915ToUnicode.cpp',
'../ucvlatin/nsISO885916ToUnicode.cpp',
'../ucvlatin/nsISO88592ToUnicode.cpp',
'../ucvlatin/nsISO88593ToUnicode.cpp',
'../ucvlatin/nsISO88594ToUnicode.cpp',
'../ucvlatin/nsISO88595ToUnicode.cpp',
'../ucvlatin/nsISO88596EToUnicode.cpp',
'../ucvlatin/nsISO88596IToUnicode.cpp',
'../ucvlatin/nsISO88596ToUnicode.cpp',
'../ucvlatin/nsISO88597ToUnicode.cpp',
'../ucvlatin/nsISO88598EToUnicode.cpp',
'../ucvlatin/nsISO88598IToUnicode.cpp',
'../ucvlatin/nsISO88598ToUnicode.cpp',
'../ucvlatin/nsISO88599ToUnicode.cpp',
'../ucvlatin/nsISOIR111ToUnicode.cpp',
'../ucvlatin/nsKOI8RToUnicode.cpp',
'../ucvlatin/nsKOI8UToUnicode.cpp',
'../ucvlatin/nsMacArabicToUnicode.cpp',
'../ucvlatin/nsMacCEToUnicode.cpp',
'../ucvlatin/nsMacCroatianToUnicode.cpp',
'../ucvlatin/nsMacCyrillicToUnicode.cpp',
'../ucvlatin/nsMacDevanagariToUnicode.cpp',
'../ucvlatin/nsMacFarsiToUnicode.cpp',
'../ucvlatin/nsMacGreekToUnicode.cpp',
'../ucvlatin/nsMacGujaratiToUnicode.cpp',
'../ucvlatin/nsMacGurmukhiToUnicode.cpp',
'../ucvlatin/nsMacHebrewToUnicode.cpp',
'../ucvlatin/nsMacIcelandicToUnicode.cpp',
'../ucvlatin/nsMacRomanianToUnicode.cpp',
'../ucvlatin/nsMacTurkishToUnicode.cpp',
'../ucvlatin/nsMUTF7ToUnicode.cpp',
'../ucvlatin/nsT61ToUnicode.cpp',
'../ucvlatin/nsTCVN5712ToUnicode.cpp',
'../ucvlatin/nsTIS620ToUnicode.cpp',
'../ucvlatin/nsUnicodeToAdobeEuro.cpp',
'../ucvlatin/nsUnicodeToARMSCII8.cpp',
'../ucvlatin/nsUnicodeToAscii.cpp',
'../ucvlatin/nsUnicodeToCP1250.cpp',
'../ucvlatin/nsUnicodeToCP1251.cpp',
'../ucvlatin/nsUnicodeToCP1253.cpp',
'../ucvlatin/nsUnicodeToCP1254.cpp',
'../ucvlatin/nsUnicodeToCP1255.cpp',
'../ucvlatin/nsUnicodeToCP1256.cpp',
'../ucvlatin/nsUnicodeToCP1257.cpp',
'../ucvlatin/nsUnicodeToCP1258.cpp',
'../ucvlatin/nsUnicodeToCP866.cpp',
'../ucvlatin/nsUnicodeToCP874.cpp',
'../ucvlatin/nsUnicodeToISO885910.cpp',
'../ucvlatin/nsUnicodeToISO885911.cpp',
'../ucvlatin/nsUnicodeToISO885913.cpp',
'../ucvlatin/nsUnicodeToISO885914.cpp',
'../ucvlatin/nsUnicodeToISO885915.cpp',
'../ucvlatin/nsUnicodeToISO885916.cpp',
'../ucvlatin/nsUnicodeToISO88592.cpp',
'../ucvlatin/nsUnicodeToISO88593.cpp',
'../ucvlatin/nsUnicodeToISO88594.cpp',
'../ucvlatin/nsUnicodeToISO88595.cpp',
'../ucvlatin/nsUnicodeToISO88596.cpp',
'../ucvlatin/nsUnicodeToISO88596E.cpp',
'../ucvlatin/nsUnicodeToISO88596I.cpp',
'../ucvlatin/nsUnicodeToISO88597.cpp',
'../ucvlatin/nsUnicodeToISO88598.cpp',
'../ucvlatin/nsUnicodeToISO88598E.cpp',
'../ucvlatin/nsUnicodeToISO88598I.cpp',
'../ucvlatin/nsUnicodeToISO88599.cpp',
'../ucvlatin/nsUnicodeToISOIR111.cpp',
'../ucvlatin/nsUnicodeToKOI8R.cpp',
'../ucvlatin/nsUnicodeToKOI8U.cpp',
'../ucvlatin/nsUnicodeToMacArabic.cpp',
'../ucvlatin/nsUnicodeToMacCE.cpp',
'../ucvlatin/nsUnicodeToMacCroatian.cpp',
'../ucvlatin/nsUnicodeToMacCyrillic.cpp',
'../ucvlatin/nsUnicodeToMacDevanagari.cpp',
'../ucvlatin/nsUnicodeToMacFarsi.cpp',
'../ucvlatin/nsUnicodeToMacGreek.cpp',
'../ucvlatin/nsUnicodeToMacGujarati.cpp',
'../ucvlatin/nsUnicodeToMacGurmukhi.cpp',
'../ucvlatin/nsUnicodeToMacHebrew.cpp',
'../ucvlatin/nsUnicodeToMacIcelandic.cpp',
'../ucvlatin/nsUnicodeToMacRomanian.cpp',
'../ucvlatin/nsUnicodeToMacTurkish.cpp',
'../ucvlatin/nsUnicodeToMUTF7.cpp',
'../ucvlatin/nsUnicodeToSymbol.cpp',
'../ucvlatin/nsUnicodeToT61.cpp',
'../ucvlatin/nsUnicodeToTCVN5712.cpp',
'../ucvlatin/nsUnicodeToTIS620.cpp',
'../ucvlatin/nsUnicodeToTSCII.cpp',
'../ucvlatin/nsUnicodeToUserDefined.cpp',
'../ucvlatin/nsUnicodeToUTF16.cpp',
'../ucvlatin/nsUnicodeToUTF7.cpp',
'../ucvlatin/nsUnicodeToVISCII.cpp',
'../ucvlatin/nsUnicodeToVPS.cpp',
'../ucvlatin/nsUnicodeToZapfDingbat.cpp',
'../ucvlatin/nsUserDefinedToUnicode.cpp',
'../ucvlatin/nsUTF16ToUnicode.cpp',
'../ucvlatin/nsUTF7ToUnicode.cpp',
'../ucvlatin/nsVISCIIToUnicode.cpp',
'../ucvlatin/nsVPSToUnicode.cpp',
]
UNIFIED_SOURCES += [
'../ucvtw/nsBIG5HKSCSToUnicode.cpp',
'../ucvtw/nsBIG5ToUnicode.cpp',
'../ucvtw/nsUnicodeToBIG5.cpp',
'../ucvtw/nsUnicodeToBIG5HKSCS.cpp',
'../ucvtw/nsUnicodeToHKSCS.cpp',
]
UNIFIED_SOURCES += [
'../ucvtw2/nsEUCTWToUnicode.cpp',
'../ucvtw2/nsUnicodeToEUCTW.cpp',
]
UNIFIED_SOURCES += [
'../util/nsUCConstructors.cpp',
'../util/nsUCSupport.cpp',
'../util/nsUnicodeDecodeHelper.cpp',
'../util/nsUnicodeEncodeHelper.cpp',
'../util/ugen.c',
'../util/umap.c',
'../util/uscan.c',
]
if CONFIG['OS_ARCH'] == 'OS2':
UNIFIED_SOURCES += [
'../ucvibm/nsCP1125ToUnicode.cpp',
'../ucvibm/nsCP1131ToUnicode.cpp',
'../ucvibm/nsCP869ToUnicode.cpp',
'../ucvibm/nsUnicodeToCP1125.cpp',
'../ucvibm/nsUnicodeToCP1131.cpp',
'../ucvibm/nsUnicodeToCP869.cpp',
]
if CONFIG['INTEL_ARCHITECTURE']:
SOURCES += [
'nsUTF8ToUnicodeSSE2.cpp',
@ -37,3 +228,7 @@ MSVC_ENABLE_PGO = True
EXPORT_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -4,26 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvcn'
EXPORTS += [
'nsUCvCnCID.h',
]
UNIFIED_SOURCES += [
'nsGBKConvUtil.cpp',
'nsGBKToUnicode.cpp',
'nsHZToUnicode.cpp',
'nsISO2022CNToUnicode.cpp',
'nsUnicodeToGB2312V2.cpp',
'nsUnicodeToGBK.cpp',
'nsUnicodeToHZ.cpp',
]
LIBRARY_NAME = 'ucvcn_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -4,41 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvibm'
EXPORTS += [
'nsUCvIBMCID.h',
]
UNIFIED_SOURCES += [
'nsCP850ToUnicode.cpp',
'nsCP852ToUnicode.cpp',
'nsCP855ToUnicode.cpp',
'nsCP857ToUnicode.cpp',
'nsCP862ToUnicode.cpp',
'nsCP864ToUnicode.cpp',
'nsUnicodeToCP850.cpp',
'nsUnicodeToCP852.cpp',
'nsUnicodeToCP855.cpp',
'nsUnicodeToCP857.cpp',
'nsUnicodeToCP862.cpp',
'nsUnicodeToCP864.cpp',
]
if CONFIG['OS_ARCH'] == 'OS2':
UNIFIED_SOURCES += [
'nsCP1125ToUnicode.cpp',
'nsCP1131ToUnicode.cpp',
'nsCP869ToUnicode.cpp',
'nsUnicodeToCP1125.cpp',
'nsUnicodeToCP1131.cpp',
'nsUnicodeToCP869.cpp',
]
LIBRARY_NAME = 'ucvibm_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -4,25 +4,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvja'
EXPORTS += [
'nsUCVJA2CID.h',
'nsUCVJACID.h',
]
UNIFIED_SOURCES += [
'nsJapaneseToUnicode.cpp',
'nsUnicodeToEUCJP.cpp',
'nsUnicodeToISO2022JP.cpp',
'nsUnicodeToJISx0201.cpp',
'nsUnicodeToSJIS.cpp',
]
LIBRARY_NAME = 'ucvja_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -13,8 +13,6 @@
#include "mozilla/Assertions.h"
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
#ifdef XP_OS2
// HTML5-incompliant behavior for OS/2, see bug 108136
// This is bogus. The right fix would be working around the font problems
@ -388,6 +386,8 @@ NS_IMETHODIMP nsISO2022JPToUnicodeV2::Convert(
const char * aSrc, int32_t * aSrcLen,
PRUnichar * aDest, int32_t * aDestLen)
{
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
static const uint16_t fbIdx[128] =
{
/* 0x8X */

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

@ -4,24 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvko'
EXPORTS += [
'nsUCvKOCID.h',
]
UNIFIED_SOURCES += [
'nsCP949ToUnicode.cpp',
'nsISO2022KRToUnicode.cpp',
'nsJohabToUnicode.cpp',
'nsUnicodeToCP949.cpp',
'nsUnicodeToJohab.cpp',
]
LIBRARY_NAME = 'ucvko_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -7,10 +7,10 @@
#include "nsICharsetConverterManager.h"
#include "nsServiceManagerUtils.h"
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
NS_IMETHODIMP nsISO2022KRToUnicode::Convert(const char * aSrc, int32_t * aSrcLen, PRUnichar * aDest, int32_t * aDestLen)
{
static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
const unsigned char* srcEnd = (unsigned char*)aSrc + *aSrcLen;
const unsigned char* src =(unsigned char*) aSrc;
PRUnichar* destEnd = aDest + *aDestLen;

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

@ -4,134 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvlatin'
EXPORTS += [
'nsUCvLatinCID.h',
]
UNIFIED_SOURCES += [
'nsARMSCII8ToUnicode.cpp',
'nsAsciiToUnicode.cpp',
'nsCP1250ToUnicode.cpp',
'nsCP1251ToUnicode.cpp',
'nsCP1253ToUnicode.cpp',
'nsCP1254ToUnicode.cpp',
'nsCP1255ToUnicode.cpp',
'nsCP1256ToUnicode.cpp',
'nsCP1257ToUnicode.cpp',
'nsCP1258ToUnicode.cpp',
'nsCP866ToUnicode.cpp',
'nsCP874ToUnicode.cpp',
'nsISO885910ToUnicode.cpp',
'nsISO885911ToUnicode.cpp',
'nsISO885913ToUnicode.cpp',
'nsISO885914ToUnicode.cpp',
'nsISO885915ToUnicode.cpp',
'nsISO885916ToUnicode.cpp',
'nsISO88592ToUnicode.cpp',
'nsISO88593ToUnicode.cpp',
'nsISO88594ToUnicode.cpp',
'nsISO88595ToUnicode.cpp',
'nsISO88596EToUnicode.cpp',
'nsISO88596IToUnicode.cpp',
'nsISO88596ToUnicode.cpp',
'nsISO88597ToUnicode.cpp',
'nsISO88598EToUnicode.cpp',
'nsISO88598IToUnicode.cpp',
'nsISO88598ToUnicode.cpp',
'nsISO88599ToUnicode.cpp',
'nsISOIR111ToUnicode.cpp',
'nsKOI8RToUnicode.cpp',
'nsKOI8UToUnicode.cpp',
'nsMacArabicToUnicode.cpp',
'nsMacCEToUnicode.cpp',
'nsMacCroatianToUnicode.cpp',
'nsMacCyrillicToUnicode.cpp',
'nsMacDevanagariToUnicode.cpp',
'nsMacFarsiToUnicode.cpp',
'nsMacGreekToUnicode.cpp',
'nsMacGujaratiToUnicode.cpp',
'nsMacGurmukhiToUnicode.cpp',
'nsMacHebrewToUnicode.cpp',
'nsMacIcelandicToUnicode.cpp',
'nsMacRomanianToUnicode.cpp',
'nsMacTurkishToUnicode.cpp',
'nsMUTF7ToUnicode.cpp',
'nsT61ToUnicode.cpp',
'nsTCVN5712ToUnicode.cpp',
'nsTIS620ToUnicode.cpp',
'nsUnicodeToAdobeEuro.cpp',
'nsUnicodeToARMSCII8.cpp',
'nsUnicodeToAscii.cpp',
'nsUnicodeToCP1250.cpp',
'nsUnicodeToCP1251.cpp',
'nsUnicodeToCP1253.cpp',
'nsUnicodeToCP1254.cpp',
'nsUnicodeToCP1255.cpp',
'nsUnicodeToCP1256.cpp',
'nsUnicodeToCP1257.cpp',
'nsUnicodeToCP1258.cpp',
'nsUnicodeToCP866.cpp',
'nsUnicodeToCP874.cpp',
'nsUnicodeToISO885910.cpp',
'nsUnicodeToISO885911.cpp',
'nsUnicodeToISO885913.cpp',
'nsUnicodeToISO885914.cpp',
'nsUnicodeToISO885915.cpp',
'nsUnicodeToISO885916.cpp',
'nsUnicodeToISO88592.cpp',
'nsUnicodeToISO88593.cpp',
'nsUnicodeToISO88594.cpp',
'nsUnicodeToISO88595.cpp',
'nsUnicodeToISO88596.cpp',
'nsUnicodeToISO88596E.cpp',
'nsUnicodeToISO88596I.cpp',
'nsUnicodeToISO88597.cpp',
'nsUnicodeToISO88598.cpp',
'nsUnicodeToISO88598E.cpp',
'nsUnicodeToISO88598I.cpp',
'nsUnicodeToISO88599.cpp',
'nsUnicodeToISOIR111.cpp',
'nsUnicodeToKOI8R.cpp',
'nsUnicodeToKOI8U.cpp',
'nsUnicodeToMacArabic.cpp',
'nsUnicodeToMacCE.cpp',
'nsUnicodeToMacCroatian.cpp',
'nsUnicodeToMacCyrillic.cpp',
'nsUnicodeToMacDevanagari.cpp',
'nsUnicodeToMacFarsi.cpp',
'nsUnicodeToMacGreek.cpp',
'nsUnicodeToMacGujarati.cpp',
'nsUnicodeToMacGurmukhi.cpp',
'nsUnicodeToMacHebrew.cpp',
'nsUnicodeToMacIcelandic.cpp',
'nsUnicodeToMacRomanian.cpp',
'nsUnicodeToMacTurkish.cpp',
'nsUnicodeToMUTF7.cpp',
'nsUnicodeToSymbol.cpp',
'nsUnicodeToT61.cpp',
'nsUnicodeToTCVN5712.cpp',
'nsUnicodeToTIS620.cpp',
'nsUnicodeToTSCII.cpp',
'nsUnicodeToUserDefined.cpp',
'nsUnicodeToUTF16.cpp',
'nsUnicodeToUTF7.cpp',
'nsUnicodeToVISCII.cpp',
'nsUnicodeToVPS.cpp',
'nsUnicodeToZapfDingbat.cpp',
'nsUserDefinedToUnicode.cpp',
'nsUTF16ToUnicode.cpp',
'nsUTF7ToUnicode.cpp',
'nsVISCIIToUnicode.cpp',
'nsVPSToUnicode.cpp',
]
LIBRARY_NAME = 'ucvlatin_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../src',
'../util',
]

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

@ -4,24 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvtw'
EXPORTS += [
'nsUCvTWCID.h',
]
UNIFIED_SOURCES += [
'nsBIG5HKSCSToUnicode.cpp',
'nsBIG5ToUnicode.cpp',
'nsUnicodeToBIG5.cpp',
'nsUnicodeToBIG5HKSCS.cpp',
'nsUnicodeToHKSCS.cpp',
]
LIBRARY_NAME = 'ucvtw_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -4,21 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'ucvtw2'
EXPORTS += [
'nsUCvTW2CID.h',
]
UNIFIED_SOURCES += [
'nsEUCTWToUnicode.cpp',
'nsUnicodeToEUCTW.cpp',
]
LIBRARY_NAME = 'ucvtw2_s'
LIBXUL_LIBRARY = True
LOCAL_INCLUDES += [
'../util',
]

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

@ -1,29 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
MODULE = 'uconv'
UNIFIED_SOURCES += [
'nsUCConstructors.cpp',
'nsUCSupport.cpp',
'nsUnicodeDecodeHelper.cpp',
'nsUnicodeEncodeHelper.cpp',
]
LIBRARY_NAME = 'ucvutil_s'
LIBXUL_LIBRARY = True
UNIFIED_SOURCES += [
'ugen.c',
'umap.c',
'uscan.c',
]
MSVC_ENABLE_PGO = True
EXPORT_LIBRARY = True

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

@ -6,7 +6,7 @@
MODULE = 'unicharutil'
SOURCES += [
UNIFIED_SOURCES += [
'nsCaseConversionImp2.cpp',
'nsCategoryImp.cpp',
'nsEntityConverter.cpp',

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

@ -8,7 +8,7 @@ MODULE = 'unicharutil'
include('../objs.mozbuild')
SOURCES += intl_unicharutil_util_cppsrcs
UNIFIED_SOURCES += intl_unicharutil_util_cppsrcs
LIBRARY_NAME = 'unicharutil_s'

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

@ -18,7 +18,7 @@ EXPORTS += [
include('objs.mozbuild')
SOURCES += intl_unicharutil_util_cppsrcs
UNIFIED_SOURCES += intl_unicharutil_util_cppsrcs
LIBRARY_NAME = 'unicharutil_external_s'

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

@ -377,6 +377,11 @@ typedef bool
typedef bool
(* DeleteSpecialOp)(JSContext *cx, JS::HandleObject obj, HandleSpecialId sid, bool *succeeded);
typedef bool
(* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
typedef bool
(* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
typedef JSObject *
(* ObjectOp)(JSContext *cx, JS::HandleObject obj);
@ -465,6 +470,8 @@ struct ObjectOps
DeletePropertyOp deleteProperty;
DeleteElementOp deleteElement;
DeleteSpecialOp deleteSpecial;
WatchOp watch;
UnwatchOp unwatch;
JSNewEnumerateOp enumerate;
ObjectOp thisObject;
@ -473,7 +480,7 @@ struct ObjectOps
#define JS_NULL_OBJECT_OPS \
{nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, \
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
} // namespace js
@ -502,7 +509,7 @@ struct JSClass {
JSNative construct;
JSTraceOp trace;
void *reserved[40];
void *reserved[42];
};
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot

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

@ -179,8 +179,8 @@ ifeq (Linux,$(OS_TARGET))
EXTRA_DSO_LDOPTS += -Wl,-version-script,symverscript
symverscript: symverscript.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
-DVERSION="$(subst -,_,$(LIBRARY_NAME))" $< > $@
$(call py_action,preprocessor, \
-DVERSION="$(subst -,_,$(LIBRARY_NAME))" $< -o $@)
EXTRA_DEPS += symverscript
endif
@ -526,14 +526,14 @@ JS_CONFIG_SUBSTITUTIONS=\
$(JS_CONFIG_NAME): js-config.in Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk $(topsrcdir)/config/rules.mk
$(RM) $@.tmp
$(PYTHON) $(topsrcdir)/config/Preprocessor.py --marker % $(JS_CONFIG_SUBSTITUTIONS) $< > $@.tmp \
&& mv $@.tmp $@ && chmod +x $@
$(call py_action,preprocessor,--marker % $(JS_CONFIG_SUBSTITUTIONS) $< -o $@.tmp)
mv $@.tmp $@ && chmod +x $@
SCRIPTS = $(JS_CONFIG_NAME)
SDK_BINARY = $(JS_CONFIG_NAME)
$(LIBRARY_NAME).pc: js.pc.in
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(JS_CONFIG_SUBSTITUTIONS) $< > $@
$(call py_action,preprocessor,$(JS_CONFIG_SUBSTITUTIONS) $< -o $@)
install:: $(LIBRARY_NAME).pc
$(SYSINSTALL) $^ $(DESTDIR)$(libdir)/pkgconfig

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

@ -774,7 +774,7 @@ HashableValue::setValue(JSContext *cx, HandleValue v)
{
if (v.isString()) {
// Atomize so that hash() and operator==() are fast and infallible.
JSString *str = AtomizeString<CanGC>(cx, v.toString(), DoNotInternAtom);
JSString *str = AtomizeString(cx, v.toString(), DoNotInternAtom);
if (!str)
return false;
value = StringValue(str);

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

@ -525,9 +525,9 @@ obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
#if JS_HAS_OBJ_WATCHPOINT
static bool
obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old,
jsval *nvp, void *closure)
bool
js::WatchHandler(JSContext *cx, JSObject *obj_, jsid id_, JS::Value old,
JS::Value *nvp, void *closure)
{
RootedObject obj(cx, obj_);
RootedId id(cx, id_);
@ -552,6 +552,15 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
if (args.length() <= 1) {
js_ReportMissingArg(cx, args.calleev(), 1);
return false;
@ -565,18 +574,16 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp)
if (!ValueToId<CanGC>(cx, args[0], &propid))
return false;
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
RootedValue tmp(cx);
unsigned attrs;
if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
return false;
args.rval().setUndefined();
if (!JSObject::watch(cx, obj, propid, callable))
return false;
return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
args.rval().setUndefined();
return true;
}
static bool
@ -587,15 +594,25 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
args.rval().setUndefined();
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
RootedId id(cx);
if (argc != 0) {
if (args.length() != 0) {
if (!ValueToId<CanGC>(cx, args[0], &id))
return false;
} else {
id = JSID_VOID;
}
return JS_ClearWatchPoint(cx, obj, id, nullptr, nullptr);
if (!JSObject::unwatch(cx, obj, id))
return false;
args.rval().setUndefined();
return true;
}
#endif /* JS_HAS_OBJ_WATCHPOINT */

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

@ -8,7 +8,8 @@
#define builtin_Object_h
#include "jsapi.h"
#include "js/Value.h"
namespace JS { class Value; }
namespace js {
@ -25,6 +26,10 @@ JSString *
ObjectToSource(JSContext *cx, JS::HandleObject obj);
#endif // JS_HAS_TOSOURCE
extern bool
WatchHandler(JSContext *cx, JSObject *obj, jsid id, JS::Value old,
JS::Value *nvp, void *closure);
} /* namespace js */
#endif /* builtin_Object_h */

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

@ -2008,7 +2008,7 @@ TypedDatum::obj_deleteElement(JSContext *cx, HandleObject obj, uint32_t index,
bool *succeeded)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id))
if (!IndexToId(cx, index, id.address()))
return false;
if (IsOwnId(cx, obj, id))
@ -2169,6 +2169,7 @@ const Class TypedObject::class_ = {
TypedDatum::obj_deleteProperty,
TypedDatum::obj_deleteElement,
TypedDatum::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
TypedDatum::obj_enumerate,
nullptr, /* thisObject */
}
@ -2259,6 +2260,7 @@ const Class TypedHandle::class_ = {
TypedDatum::obj_deleteProperty,
TypedDatum::obj_deleteElement,
TypedDatum::obj_deleteSpecial,
nullptr, nullptr, // watch/unwatch
TypedDatum::obj_enumerate,
nullptr, /* thisObject */
}

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

@ -1,241 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Parses and evaluates simple statements for Preprocessor:
Expression currently supports the following grammar, whitespace is ignored:
expression :
and_cond ( '||' expression ) ? ;
and_cond:
test ( '&&' and_cond ) ? ;
test:
unary ( ( '==' | '!=' ) unary ) ? ;
unary :
'!'? value ;
value :
[0-9]+ # integer
| 'defined(' \w+ ')'
| \w+ # string identifier or value;
"""
import re
class Expression:
def __init__(self, expression_string):
"""
Create a new expression with this string.
The expression will already be parsed into an Abstract Syntax Tree.
"""
self.content = expression_string
self.offset = 0
self.__ignore_whitespace()
self.e = self.__get_logical_or()
if self.content:
raise Expression.ParseError, self
def __get_logical_or(self):
"""
Production: and_cond ( '||' expression ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("logical_op")
# test
rv.append(self.__get_logical_and())
self.__ignore_whitespace()
if self.content[:2] != '||':
# no logical op needed, short cut to our prime element
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_logical_or())
self.__ignore_whitespace()
return rv
def __get_logical_and(self):
"""
Production: test ( '&&' and_cond ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("logical_op")
# test
rv.append(self.__get_equality())
self.__ignore_whitespace()
if self.content[:2] != '&&':
# no logical op needed, short cut to our prime element
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_logical_and())
self.__ignore_whitespace()
return rv
def __get_equality(self):
"""
Production: unary ( ( '==' | '!=' ) unary ) ?
"""
if not len(self.content):
return None
rv = Expression.__AST("equality")
# unary
rv.append(self.__get_unary())
self.__ignore_whitespace()
if not re.match('[=!]=', self.content):
# no equality needed, short cut to our prime unary
return rv[0]
# append operator
rv.append(Expression.__ASTLeaf('op', self.content[:2]))
self.__strip(2)
self.__ignore_whitespace()
rv.append(self.__get_unary())
self.__ignore_whitespace()
return rv
def __get_unary(self):
"""
Production: '!'? value
"""
# eat whitespace right away, too
not_ws = re.match('!\s*', self.content)
if not not_ws:
return self.__get_value()
rv = Expression.__AST('not')
self.__strip(not_ws.end())
rv.append(self.__get_value())
self.__ignore_whitespace()
return rv
def __get_value(self):
"""
Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ )
Note that the order is important, and the expression is kind-of
ambiguous as \w includes 0-9. One could make it unambiguous by
removing 0-9 from the first char of a string literal.
"""
rv = None
m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content)
if m:
word_len = m.end()
rv = Expression.__ASTLeaf('defined', m.group(1))
else:
word_len = re.match('[0-9]*', self.content).end()
if word_len:
value = int(self.content[:word_len])
rv = Expression.__ASTLeaf('int', value)
else:
word_len = re.match('\w*', self.content).end()
if word_len:
rv = Expression.__ASTLeaf('string', self.content[:word_len])
else:
raise Expression.ParseError, self
self.__strip(word_len)
self.__ignore_whitespace()
return rv
def __ignore_whitespace(self):
ws_len = re.match('\s*', self.content).end()
self.__strip(ws_len)
return
def __strip(self, length):
"""
Remove a given amount of chars from the input and update
the offset.
"""
self.content = self.content[length:]
self.offset += length
def evaluate(self, context):
"""
Evaluate the expression with the given context
"""
# Helper function to evaluate __get_equality results
def eval_equality(tok):
left = opmap[tok[0].type](tok[0])
right = opmap[tok[2].type](tok[2])
rv = left == right
if tok[1].value == '!=':
rv = not rv
return rv
# Helper function to evaluate __get_logical_and and __get_logical_or results
def eval_logical_op(tok):
left = opmap[tok[0].type](tok[0])
right = opmap[tok[2].type](tok[2])
if tok[1].value == '&&':
return left and right
elif tok[1].value == '||':
return left or right
raise Expression.ParseError, self
# Mapping from token types to evaluator functions
# Apart from (non-)equality, all these can be simple lambda forms.
opmap = {
'logical_op': eval_logical_op,
'equality': eval_equality,
'not': lambda tok: not opmap[tok[0].type](tok[0]),
'string': lambda tok: context[tok.value],
'defined': lambda tok: tok.value in context,
'int': lambda tok: tok.value}
return opmap[self.e.type](self.e);
class __AST(list):
"""
Internal class implementing Abstract Syntax Tree nodes
"""
def __init__(self, type):
self.type = type
super(self.__class__, self).__init__(self)
class __ASTLeaf:
"""
Internal class implementing Abstract Syntax Tree leafs
"""
def __init__(self, type, value):
self.value = value
self.type = type
def __str__(self):
return self.value.__str__()
def __repr__(self):
return self.value.__repr__()
class ParseError(StandardError):
"""
Error raised when parsing fails.
It has two members, offset and content, which give the offset of the
error and the offending content.
"""
def __init__(self, expression):
self.offset = expression.offset
self.content = expression.content[:3]
def __str__(self):
return 'Unexpected content at offset {0}, "{1}"'.format(self.offset,
self.content)
class Context(dict):
"""
This class holds variable values by subclassing dict, and while it
truthfully reports True and False on
name in context
it returns the variable name itself on
context["name"]
to reflect the ambiguity between string literals and preprocessor
variables.
"""
def __getitem__(self, key):
if key in self:
return super(self.__class__, self).__getitem__(key)
return key

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

@ -40,7 +40,7 @@ ifdef WRAP_SYSTEM_INCLUDES
export:: \
$(call mkdir_deps,system_wrappers_js) \
$(NULL)
$(PYTHON) $(srcdir)/Preprocessor.py $(DEFINES) $(ACDEFINES) \
$(PYTHON) -m mozbuild.action.preprocessor $(DEFINES) $(ACDEFINES) \
-DMOZ_NATIVE_ICU=$(MOZ_NATIVE_ICU) \
$(srcdir)/system-headers | $(PERL) $(srcdir)/make-system-wrappers.pl system_wrappers_js
$(INSTALL) system_wrappers_js $(DIST)

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

@ -1,492 +0,0 @@
"""
This is a very primitive line based preprocessor, for times when using
a C preprocessor isn't an option.
"""
# 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/.
import sys
import os
import os.path
import re
from optparse import OptionParser
import errno
# hack around win32 mangling our line endings
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
if sys.platform == "win32":
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
os.linesep = '\n'
import Expression
__all__ = ['Preprocessor', 'preprocess']
class Preprocessor:
"""
Class for preprocessing text files.
"""
class Error(RuntimeError):
def __init__(self, cpp, MSG, context):
self.file = cpp.context['FILE']
self.line = cpp.context['LINE']
self.key = MSG
RuntimeError.__init__(self, (self.file, self.line, self.key, context))
def __init__(self):
self.context = Expression.Context()
for k,v in {'FILE': '',
'LINE': 0,
'DIRECTORY': os.path.abspath('.')}.iteritems():
self.context[k] = v
self.actionLevel = 0
self.disableLevel = 0
# ifStates can be
# 0: hadTrue
# 1: wantsTrue
# 2: #else found
self.ifStates = []
self.checkLineNumbers = False
self.writtenLines = 0
self.filters = []
self.cmds = {}
for cmd, level in {'define': 0,
'undef': 0,
'if': sys.maxint,
'ifdef': sys.maxint,
'ifndef': sys.maxint,
'else': 1,
'elif': 1,
'elifdef': 1,
'elifndef': 1,
'endif': sys.maxint,
'expand': 0,
'literal': 0,
'filter': 0,
'unfilter': 0,
'include': 0,
'includesubst': 0,
'error': 0}.iteritems():
self.cmds[cmd] = (level, getattr(self, 'do_' + cmd))
self.out = sys.stdout
self.setMarker('#')
self.LE = '\n'
self.varsubst = re.compile('@(?P<VAR>\w+)@', re.U)
def warnUnused(self, file):
if self.actionLevel == 0:
sys.stderr.write('{0}: WARNING: no preprocessor directives found\n'.format(file))
elif self.actionLevel == 1:
sys.stderr.write('{0}: WARNING: no useful preprocessor directives found\n'.format(file))
pass
def setLineEndings(self, aLE):
"""
Set the line endings to be used for output.
"""
self.LE = {'cr': '\x0D', 'lf': '\x0A', 'crlf': '\x0D\x0A'}[aLE]
def setMarker(self, aMarker):
"""
Set the marker to be used for processing directives.
Used for handling CSS files, with pp.setMarker('%'), for example.
The given marker may be None, in which case no markers are processed.
"""
self.marker = aMarker
if aMarker:
self.instruction = re.compile('{0}(?P<cmd>[a-z]+)(?:\s(?P<args>.*))?$'
.format(aMarker),
re.U)
self.comment = re.compile(aMarker, re.U)
else:
class NoMatch(object):
def match(self, *args):
return False
self.instruction = self.comment = NoMatch()
def clone(self):
"""
Create a clone of the current processor, including line ending
settings, marker, variable definitions, output stream.
"""
rv = Preprocessor()
rv.context.update(self.context)
rv.setMarker(self.marker)
rv.LE = self.LE
rv.out = self.out
return rv
def applyFilters(self, aLine):
for f in self.filters:
aLine = f[1](aLine)
return aLine
def write(self, aLine):
"""
Internal method for handling output.
"""
if self.checkLineNumbers:
self.writtenLines += 1
ln = self.context['LINE']
if self.writtenLines != ln:
self.out.write('//@line {line} "{file}"{le}'.format(line=ln,
file=self.context['FILE'],
le=self.LE))
self.writtenLines = ln
filteredLine = self.applyFilters(aLine)
if filteredLine != aLine:
self.actionLevel = 2
# ensure our line ending. Only need to handle \n, as we're reading
# with universal line ending support, at least for files.
filteredLine = re.sub('\n', self.LE, filteredLine)
self.out.write(filteredLine)
def handleCommandLine(self, args, defaultToStdin = False):
"""
Parse a commandline into this parser.
Uses OptionParser internally, no args mean sys.argv[1:].
"""
p = self.getCommandLineParser()
(options, args) = p.parse_args(args=args)
includes = options.I
if options.output:
dir = os.path.dirname(options.output)
if dir and not os.path.exists(dir):
try:
os.makedirs(dir)
except OSError as error:
if error.errno != errno.EEXIST:
raise
self.out = open(options.output, 'wb')
if defaultToStdin and len(args) == 0:
args = [sys.stdin]
includes.extend(args)
if includes:
for f in includes:
self.do_include(f, False)
self.warnUnused(f)
pass
def getCommandLineParser(self, unescapeDefines = False):
escapedValue = re.compile('".*"$')
numberValue = re.compile('\d+$')
def handleE(option, opt, value, parser):
for k,v in os.environ.iteritems():
self.context[k] = v
def handleD(option, opt, value, parser):
vals = value.split('=', 1)
if len(vals) == 1:
vals.append(1)
elif unescapeDefines and escapedValue.match(vals[1]):
# strip escaped string values
vals[1] = vals[1][1:-1]
elif numberValue.match(vals[1]):
vals[1] = int(vals[1])
self.context[vals[0]] = vals[1]
def handleU(option, opt, value, parser):
del self.context[value]
def handleF(option, opt, value, parser):
self.do_filter(value)
def handleLE(option, opt, value, parser):
self.setLineEndings(value)
def handleMarker(option, opt, value, parser):
self.setMarker(value)
p = OptionParser()
p.add_option('-I', action='append', type="string", default = [],
metavar="FILENAME", help='Include file')
p.add_option('-E', action='callback', callback=handleE,
help='Import the environment into the defined variables')
p.add_option('-D', action='callback', callback=handleD, type="string",
metavar="VAR[=VAL]", help='Define a variable')
p.add_option('-U', action='callback', callback=handleU, type="string",
metavar="VAR", help='Undefine a variable')
p.add_option('-F', action='callback', callback=handleF, type="string",
metavar="FILTER", help='Enable the specified filter')
p.add_option('-o', '--output', type="string", default=None,
metavar="FILENAME", help='Output to the specified file '+
'instead of stdout')
p.add_option('--line-endings', action='callback', callback=handleLE,
type="string", metavar="[cr|lr|crlf]",
help='Use the specified line endings [Default: OS dependent]')
p.add_option('--marker', action='callback', callback=handleMarker,
type="string",
help='Use the specified marker instead of #')
return p
def handleLine(self, aLine):
"""
Handle a single line of input (internal).
"""
if self.actionLevel == 0 and self.comment.match(aLine):
self.actionLevel = 1
m = self.instruction.match(aLine)
if m:
args = None
cmd = m.group('cmd')
try:
args = m.group('args')
except IndexError:
pass
if cmd not in self.cmds:
raise Preprocessor.Error(self, 'INVALID_CMD', aLine)
level, cmd = self.cmds[cmd]
if (level >= self.disableLevel):
cmd(args)
if cmd != 'literal':
self.actionLevel = 2
elif self.disableLevel == 0 and not self.comment.match(aLine):
self.write(aLine)
pass
# Instruction handlers
# These are named do_'instruction name' and take one argument
# Variables
def do_define(self, args):
m = re.match('(?P<name>\w+)(?:\s(?P<value>.*))?', args, re.U)
if not m:
raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
val = 1
if m.group('value'):
val = self.applyFilters(m.group('value'))
try:
val = int(val)
except:
pass
self.context[m.group('name')] = val
def do_undef(self, args):
m = re.match('(?P<name>\w+)$', args, re.U)
if not m:
raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
if args in self.context:
del self.context[args]
# Logic
def ensure_not_else(self):
if len(self.ifStates) == 0 or self.ifStates[-1] == 2:
sys.stderr.write('WARNING: bad nesting of #else\n')
def do_if(self, args, replace=False):
if self.disableLevel and not replace:
self.disableLevel += 1
return
val = None
try:
e = Expression.Expression(args)
val = e.evaluate(self.context)
except Exception:
# XXX do real error reporting
raise Preprocessor.Error(self, 'SYNTAX_ERR', args)
if type(val) == str:
# we're looking for a number value, strings are false
val = False
if not val:
self.disableLevel = 1
if replace:
if val:
self.disableLevel = 0
self.ifStates[-1] = self.disableLevel
else:
self.ifStates.append(self.disableLevel)
pass
def do_ifdef(self, args, replace=False):
if self.disableLevel and not replace:
self.disableLevel += 1
return
if re.match('\W', args, re.U):
raise Preprocessor.Error(self, 'INVALID_VAR', args)
if args not in self.context:
self.disableLevel = 1
if replace:
if args in self.context:
self.disableLevel = 0
self.ifStates[-1] = self.disableLevel
else:
self.ifStates.append(self.disableLevel)
pass
def do_ifndef(self, args, replace=False):
if self.disableLevel and not replace:
self.disableLevel += 1
return
if re.match('\W', args, re.U):
raise Preprocessor.Error(self, 'INVALID_VAR', args)
if args in self.context:
self.disableLevel = 1
if replace:
if args not in self.context:
self.disableLevel = 0
self.ifStates[-1] = self.disableLevel
else:
self.ifStates.append(self.disableLevel)
pass
def do_else(self, args, ifState = 2):
self.ensure_not_else()
hadTrue = self.ifStates[-1] == 0
self.ifStates[-1] = ifState # in-else
if hadTrue:
self.disableLevel = 1
return
self.disableLevel = 0
def do_elif(self, args):
if self.disableLevel == 1:
if self.ifStates[-1] == 1:
self.do_if(args, replace=True)
else:
self.do_else(None, self.ifStates[-1])
def do_elifdef(self, args):
if self.disableLevel == 1:
if self.ifStates[-1] == 1:
self.do_ifdef(args, replace=True)
else:
self.do_else(None, self.ifStates[-1])
def do_elifndef(self, args):
if self.disableLevel == 1:
if self.ifStates[-1] == 1:
self.do_ifndef(args, replace=True)
else:
self.do_else(None, self.ifStates[-1])
def do_endif(self, args):
if self.disableLevel > 0:
self.disableLevel -= 1
if self.disableLevel == 0:
self.ifStates.pop()
# output processing
def do_expand(self, args):
lst = re.split('__(\w+)__', args, re.U)
do_replace = False
def vsubst(v):
if v in self.context:
return str(self.context[v])
return ''
for i in range(1, len(lst), 2):
lst[i] = vsubst(lst[i])
lst.append('\n') # add back the newline
self.write(reduce(lambda x, y: x+y, lst, ''))
def do_literal(self, args):
self.write(args + self.LE)
def do_filter(self, args):
filters = [f for f in args.split(' ') if hasattr(self, 'filter_' + f)]
if len(filters) == 0:
return
current = dict(self.filters)
for f in filters:
current[f] = getattr(self, 'filter_' + f)
filterNames = current.keys()
filterNames.sort()
self.filters = [(fn, current[fn]) for fn in filterNames]
return
def do_unfilter(self, args):
filters = args.split(' ')
current = dict(self.filters)
for f in filters:
if f in current:
del current[f]
filterNames = current.keys()
filterNames.sort()
self.filters = [(fn, current[fn]) for fn in filterNames]
return
# Filters
#
# emptyLines
# Strips blank lines from the output.
def filter_emptyLines(self, aLine):
if aLine == '\n':
return ''
return aLine
# slashslash
# Strips everything after //
def filter_slashslash(self, aLine):
if (aLine.find('//') == -1):
return aLine
[aLine, rest] = aLine.split('//', 1)
if rest:
aLine += '\n'
return aLine
# spaces
# Collapses sequences of spaces into a single space
def filter_spaces(self, aLine):
return re.sub(' +', ' ', aLine).strip(' ')
# substition
# helper to be used by both substition and attemptSubstitution
def filter_substitution(self, aLine, fatal=True):
def repl(matchobj):
varname = matchobj.group('VAR')
if varname in self.context:
return str(self.context[varname])
if fatal:
raise Preprocessor.Error(self, 'UNDEFINED_VAR', varname)
return matchobj.group(0)
return self.varsubst.sub(repl, aLine)
def filter_attemptSubstitution(self, aLine):
return self.filter_substitution(aLine, fatal=False)
# File ops
def do_include(self, args, filters=True):
"""
Preprocess a given file.
args can either be a file name, or a file-like object.
Files should be opened, and will be closed after processing.
"""
isName = type(args) == str or type(args) == unicode
oldWrittenLines = self.writtenLines
oldCheckLineNumbers = self.checkLineNumbers
self.checkLineNumbers = False
if isName:
try:
args = str(args)
if filters:
args = self.applyFilters(args)
if not os.path.isabs(args):
args = os.path.join(self.context['DIRECTORY'], args)
args = open(args, 'rU')
except Preprocessor.Error:
raise
except:
raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args))
self.checkLineNumbers = bool(re.search('\.(js|jsm|java)(?:\.in)?$', args.name))
oldFile = self.context['FILE']
oldLine = self.context['LINE']
oldDir = self.context['DIRECTORY']
if args.isatty():
# we're stdin, use '-' and '' for file and dir
self.context['FILE'] = '-'
self.context['DIRECTORY'] = ''
else:
abspath = os.path.abspath(args.name)
self.context['FILE'] = abspath
self.context['DIRECTORY'] = os.path.dirname(abspath)
self.context['LINE'] = 0
self.writtenLines = 0
for l in args:
self.context['LINE'] += 1
self.handleLine(l)
args.close()
self.context['FILE'] = oldFile
self.checkLineNumbers = oldCheckLineNumbers
self.writtenLines = oldWrittenLines
self.context['LINE'] = oldLine
self.context['DIRECTORY'] = oldDir
def do_includesubst(self, args):
args = self.filter_substitution(args)
self.do_include(args)
def do_error(self, args):
raise Preprocessor.Error(self, 'Error: ', str(args))
def main():
pp = Preprocessor()
pp.handleCommandLine(None, True)
return
def preprocess(includes=[sys.stdin], defines={},
output = sys.stdout,
line_endings='\n', marker='#'):
pp = Preprocessor()
pp.context.update(defines)
pp.setLineEndings(line_endings)
pp.setMarker(marker)
pp.out = output
for f in includes:
pp.do_include(f, False)
if __name__ == "__main__":
main()

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

@ -53,7 +53,7 @@ else
REPORT_BUILD = $(info $(shell $(PYTHON) $(MOZILLA_DIR)/config/rebuild_check.py $@ $^))
endif
else
REPORT_BUILD = $(info $(notdir $@))
REPORT_BUILD = $(info $(if $(filter $(DEPTH)/%,$@),$(@:$(DEPTH)/%=%),$(notdir $@)))
endif
ifeq ($(OS_ARCH),OS2)
@ -1481,6 +1481,11 @@ endif
#
# Additionally, a FOO_TARGET variable may be added to indicate the target for
# which the files and executables are installed. Default is "libs".
#
# Finally, a FOO_KEEP_PATH variable may be set to 1 to indicate the paths given
# in FOO_FILES/FOO_EXECUTABLES are to be kept at the destination. That is,
# if FOO_FILES is bar/baz/qux.h, and FOO_DEST is $(DIST)/include, the installed
# file would be $(DIST)/include/bar/baz/qux.h instead of $(DIST)/include/qux.h
# If we're using binary nsinstall and it's not built yet, fallback to python nsinstall.
ifneq (,$(filter $(CONFIG_TOOLS)/nsinstall$(HOST_BIN_SUFFIX),$(install_cmd)))
@ -1493,22 +1498,52 @@ endef
endif
endif
define install_file_template
$(or $(3),libs):: $(2)/$(notdir $(1))
$(call install_cmd_override,$(2)/$(notdir $(1)))
$(2)/$(notdir $(1)): $(1)
$$(call install_cmd,$(4) "$$<" "$${@D}")
install_target_tier = $(or $($(1)_TARGET),libs)
INSTALL_TARGETS_TIERS := $(sort $(foreach category,$(INSTALL_TARGETS),$(call install_target_tier,$(category))))
install_target_result = $($(1)_DEST:%/=%)/$(if $($(1)_KEEP_PATH),$(2),$(notdir $(2)))
install_target_files = $(foreach file,$($(1)_FILES),$(call install_target_result,$(category),$(file)))
install_target_executables = $(foreach file,$($(1)_EXECUTABLES),$(call install_target_result,$(category),$(file)))
# Work around a GNU make 3.81 bug where it gives $< the wrong value.
# See details in bug 934864.
define create_dependency
$(1): $(2)
$(1): $(2)
endef
define install_target_template
$(call install_cmd_override,$(2))
$(call create_dependency,$(2),$(1))
endef
$(foreach category,$(INSTALL_TARGETS),\
$(if $($(category)_DEST),,$(error Missing $(category)_DEST))\
$(foreach file,$($(category)_FILES),\
$(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS1)))\
)\
$(foreach file,$($(category)_EXECUTABLES),\
$(eval $(call install_file_template,$(file),$($(category)_DEST),$($(category)_TARGET),$(IFLAGS2)))\
)\
$(if $($(category)_DEST),,$(error Missing $(category)_DEST)) \
$(foreach tier,$(call install_target_tier,$(category)),\
$(eval INSTALL_TARGETS_FILES_$(tier) += $(call install_target_files,$(category))) \
$(eval INSTALL_TARGETS_EXECUTABLES_$(tier) += $(call install_target_executables,$(category))) \
) \
$(foreach file,$($(category)_FILES) $($(category)_EXECUTABLES), \
$(eval $(call install_target_template,$(file),$(call install_target_result,$(category),$(file)))) \
) \
)
$(foreach tier,$(INSTALL_TARGETS_TIERS), \
$(eval $(tier):: $(INSTALL_TARGETS_FILES_$(tier)) $(INSTALL_TARGETS_EXECUTABLES_$(tier))) \
)
install_targets_sanity = $(if $(filter-out $(notdir $@),$(notdir $(<))),$(error Looks like $@ has an unexpected dependency on $< which breaks INSTALL_TARGETS))
$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_FILES_$(tier)))):
$(install_targets_sanity)
$(REPORT_BUILD)
$(call install_cmd,$(IFLAGS1) "$<" "$(@D)")
$(sort $(foreach tier,$(INSTALL_TARGETS_TIERS),$(INSTALL_TARGETS_EXECUTABLES_$(tier)))):
$(install_targets_sanity)
$(REPORT_BUILD)
$(call install_cmd,$(IFLAGS2) "$<" "$(@D)")
################################################################################
# Preprocessing rules
#
@ -1524,40 +1559,80 @@ $(foreach category,$(INSTALL_TARGETS),\
# If PP_TARGETS lists a category name <C> (like FOO, above), then we consult the
# following make variables to see what to do:
#
# - <C> lists input files to be preprocessed with config/Preprocessor.py. We
# search VPATH for the names given here. If an input file name ends in '.in',
# that suffix is omitted from the output file name.
# - <C> lists input files to be preprocessed with mozbuild.action.preprocessor.
# We search VPATH for the names given here. If an input file name ends in
# '.in', that suffix is omitted from the output file name.
#
# - <C>_PATH names the directory in which to place the preprocessed output
# files. We create this directory if it does not already exist. Setting
# this variable is optional; if unset, we install the files in $(CURDIR).
#
# - <C>_FLAGS lists flags to pass to Preprocessor.py, in addition to the usual
# bunch. Setting this variable is optional.
# - <C>_FLAGS lists flags to pass to mozbuild.action.preprocessor, in addition
# to the usual bunch. Setting this variable is optional.
#
# - <C>_TARGET names the 'make' target that should depend on creating the output
# files. Setting this variable is optional; if unset, we preprocess the
# files for the 'libs' target.
#
# - <C>_KEEP_PATH may be set to 1 to indicate the paths given in <C> are to be
# kept under <C>_PATH. That is, if <C> is bar/baz/qux.h.in and <C>_PATH is
# $(DIST)/include, the preprocessed file would be $(DIST)/include/bar/baz/qux.h
# instead of $(DIST)/include/qux.h.
# preprocess_file_template defines preprocessing rules.
# $(call preprocess_file_template, source_file, output_file,
# makefile_target, extra_flags)
define preprocess_file_template
$(2): $(1) $$(GLOBAL_DEPS)
$$(RM) "$$@"
$$(PYTHON) $$(topsrcdir)/config/Preprocessor.py $(4) $$(DEFINES) $$(ACDEFINES) $$(XULPPFLAGS) "$$<" -o "$$@"
$(3):: $(2)
endef
pp_target_tier = $(or $($(1)_TARGET),libs)
PP_TARGETS_TIERS := $(sort $(foreach category,$(PP_TARGETS),$(call pp_target_tier,$(category))))
$(foreach category,$(PP_TARGETS), \
$(foreach file,$($(category)), \
$(eval $(call preprocess_file_template, \
$(file), \
$(or $($(category)_PATH),$(CURDIR))/$(notdir $(file:.in=)), \
$(or $($(category)_TARGET),libs), \
$($(category)_FLAGS))) \
) \
)
pp_target_result = $(or $($(1)_PATH:%/=%),$(CURDIR))/$(if $($(1)_KEEP_PATH),$(2:.in=),$(notdir $(2:.in=)))
pp_target_results = $(foreach file,$($(1)),$(call pp_target_result,$(category),$(file)))
$(foreach category,$(PP_TARGETS), \
$(foreach tier,$(call pp_target_tier,$(category)), \
$(eval PP_TARGETS_RESULTS_$(tier) += $(call pp_target_results,$(category))) \
) \
$(foreach file,$($(category)), \
$(eval $(call create_dependency,$(call pp_target_result,$(category),$(file)), \
$(file) $(GLOBAL_DEPS))) \
) \
$(eval $(call pp_target_results,$(category)): PP_TARGET_FLAGS=$($(category)_FLAGS)) \
)
$(foreach tier,$(PP_TARGETS_TIERS), \
$(eval $(tier):: $(PP_TARGETS_RESULTS_$(tier))) \
)
PP_TARGETS_ALL_RESULTS := $(sort $(foreach tier,$(PP_TARGETS_TIERS),$(PP_TARGETS_RESULTS_$(tier))))
$(PP_TARGETS_ALL_RESULTS):
$(if $(filter-out $(notdir $@),$(notdir $(<:.in=))),$(error Looks like $@ has an unexpected dependency on $< which breaks PP_TARGETS))
$(REPORT_BUILD)
$(RM) "$@"
$(call py_action,preprocessor,--depend $(MDDEPDIR)/$(@F).pp $(PP_TARGET_FLAGS) $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) "$<" -o "$@")
# The depfile is based on the filename, and we don't want conflicts. So check
# there's only one occurrence of any given filename in PP_TARGETS_ALL_RESULTS.
PP_TARGETS_ALL_RESULT_NAMES := $(notdir $(PP_TARGETS_ALL_RESULTS))
$(foreach file,$(sort $(PP_TARGETS_ALL_RESULT_NAMES)), \
$(if $(filter-out 1,$(words $(filter $(file),$(PP_TARGETS_ALL_RESULT_NAMES)))), \
$(error Multiple preprocessing rules are creating a $(file) file) \
) \
)
ifneq (,$(filter $(PP_TARGETS_TIERS) $(PP_TARGETS_ALL_RESULTS),$(MAKECMDGOALS)))
# If the depfile for a preprocessed file doesn't exist, add a dep to force
# re-preprocessing.
$(foreach file,$(PP_TARGETS_ALL_RESULTS), \
$(if $(wildcard $(MDDEPDIR)/$(notdir $(file)).pp), \
, \
$(eval $(file): FORCE) \
) \
)
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(addsuffix .pp,$(notdir $(PP_TARGETS_ALL_RESULTS))))))
ifneq (,$(MDDEPEND_FILES))
$(call include_deps,$(MDDEPEND_FILES))
endif
endif
# Pull in non-recursive targets if this is a partial tree build.
ifndef TOPLEVEL_BUILD

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

@ -282,7 +282,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
* Save eval program source in script->atoms[0] for the
* eval cache (see EvalCacheLookup in jsobj.cpp).
*/
JSAtom *atom = AtomizeString<CanGC>(cx, source);
JSAtom *atom = AtomizeString(cx, source);
jsatomid _;
if (!atom || !bce.makeAtomIndex(atom, &_))
return nullptr;

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