зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
37ac775340
|
@ -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) \
|
||||
|
|
147
config/rules.mk
147
config/rules.mk
|
@ -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, ®s[0], ®s[1], ®s[2], ®s[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;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче