Merge inbound to m-c

This commit is contained in:
Wes Kocher 2013-10-11 18:50:09 -07:00
commit b2af114078
69 changed files with 1696 additions and 975 deletions

View File

@ -62,8 +62,9 @@ let gGestureSupport = {
switch (aEvent.type) {
case "MozSwipeGestureStart":
aEvent.preventDefault();
this._setupSwipeGesture(aEvent);
if (this._setupSwipeGesture(aEvent)) {
aEvent.preventDefault();
}
break;
case "MozSwipeGestureUpdate":
aEvent.preventDefault();
@ -179,23 +180,43 @@ let gGestureSupport = {
*
* @param aEvent
* The swipe gesture start event.
* @return true if swipe gestures could successfully be set up, false
* othwerwise.
*/
_setupSwipeGesture: function GS__setupSwipeGesture(aEvent) {
if (!this._swipeNavigatesHistory(aEvent))
return;
if (!this._swipeNavigatesHistory(aEvent)) {
return false;
}
let isVerticalSwipe = false;
if (gHistorySwipeAnimation.active) {
if (aEvent.direction == aEvent.DIRECTION_UP) {
if (content.pageYOffset > 0) {
return false;
}
isVerticalSwipe = true;
} else if (aEvent.direction == aEvent.DIRECTION_DOWN) {
if (content.pageYOffset < content.scrollMaxY) {
return false;
}
isVerticalSwipe = true;
}
}
let canGoBack = gHistorySwipeAnimation.canGoBack();
let canGoForward = gHistorySwipeAnimation.canGoForward();
let isLTR = gHistorySwipeAnimation.isLTR;
if (canGoBack)
if (canGoBack) {
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_LEFT :
aEvent.DIRECTION_RIGHT;
if (canGoForward)
}
if (canGoForward) {
aEvent.allowedDirections |= isLTR ? aEvent.DIRECTION_RIGHT :
aEvent.DIRECTION_LEFT;
}
gHistorySwipeAnimation.startAnimation();
gHistorySwipeAnimation.startAnimation(isVerticalSwipe);
this._doUpdate = function GS__doUpdate(aEvent) {
gHistorySwipeAnimation.updateAnimation(aEvent.delta);
@ -207,6 +228,8 @@ let gGestureSupport = {
this._doUpdate = function (aEvent) {};
this._doEnd = function (aEvent) {};
}
return true;
},
/**
@ -552,8 +575,10 @@ let gHistorySwipeAnimation = {
this._startingIndex = -1;
this._historyIndex = -1;
this._boxWidth = -1;
this._boxHeight = -1;
this._maxSnapshots = this._getMaxSnapshots();
this._lastSwipeDir = "";
this._direction = "horizontal";
// We only want to activate history swipe animations if we store snapshots.
// If we don't store any, we handle horizontal swipes without animations.
@ -584,14 +609,28 @@ let gHistorySwipeAnimation = {
/**
* Starts the swipe animation and handles fast swiping (i.e. a swipe animation
* is already in progress when a new one is initiated).
*
* @param aIsVerticalSwipe
* Whether we're dealing with a vertical swipe or not.
*/
startAnimation: function HSA_startAnimation() {
startAnimation: function HSA_startAnimation(aIsVerticalSwipe) {
this._direction = aIsVerticalSwipe ? "vertical" : "horizontal";
if (this.isAnimationRunning()) {
gBrowser.stop();
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
this._handleFastSwiping();
// If this is a horizontal scroll, or if this is a vertical scroll that
// was started while a horizontal scroll was still running, handle it as
// as a fast swipe. In the case of the latter scenario, this allows us to
// start the vertical animation without first loading the final page, or
// taking another snapshot. If vertical scrolls are initiated repeatedly
// without prior horizontal scroll we skip this and restart the animation
// from 0.
if (this._direction == "horizontal" || this._lastSwipeDir != "") {
gBrowser.stop();
this._lastSwipeDir = "RELOAD"; // just ensure that != ""
this._canGoBack = this.canGoBack();
this._canGoForward = this.canGoForward();
this._handleFastSwiping();
}
}
else {
this._startingIndex = gBrowser.webNavigation.sessionHistory.index;
@ -623,19 +662,24 @@ let gHistorySwipeAnimation = {
* swipe gesture.
*/
updateAnimation: function HSA_updateAnimation(aVal) {
if (!this.isAnimationRunning())
if (!this.isAnimationRunning()) {
return;
}
// We use the following value to decrease the bounce effect when swiping
// back/forward past the browsing history. This value was determined
// experimentally.
// We use the following value to decrease the bounce effect when scrolling
// to the top or bottom of the page, or when swiping back/forward past the
// browsing history. This value was determined experimentally.
let dampValue = 4;
if ((aVal >= 0 && this.isLTR) ||
(aVal <= 0 && !this.isLTR)) {
if (this._direction == "vertical") {
this._prevBox.collapsed = true;
this._nextBox.collapsed = true;
this._positionBox(this._curBox, -1 * aVal / dampValue);
} else if ((aVal >= 0 && this.isLTR) ||
(aVal <= 0 && !this.isLTR)) {
let tempDampValue = 1;
if (this._canGoBack)
if (this._canGoBack) {
this._prevBox.collapsed = false;
else {
} else {
tempDampValue = dampValue;
this._prevBox.collapsed = true;
}
@ -647,11 +691,7 @@ let gHistorySwipeAnimation = {
// The forward page should be pushed offscreen all the way to the right.
this._positionBox(this._nextBox, 1);
}
else {
if (aVal < -1)
aVal = -1; // Cap value to avoid sliding the page further than allowed.
} else {
// The intention is to go forward. If there is a page to go forward to,
// it should slide in from the right (LTR) or left (RTL).
// Otherwise, the current page should slide to the left (LTR) or
@ -663,8 +703,7 @@ let gHistorySwipeAnimation = {
let offset = this.isLTR ? 1 : -1;
this._positionBox(this._curBox, 0);
this._positionBox(this._nextBox, offset + aVal);
}
else {
} else {
this._prevBox.collapsed = true;
this._positionBox(this._curBox, aVal / dampValue);
}
@ -835,7 +874,9 @@ let gHistorySwipeAnimation = {
"box");
this._container.appendChild(this._nextBox);
this._boxWidth = this._curBox.getBoundingClientRect().width; // cache width
// Cache width and height.
this._boxWidth = this._curBox.getBoundingClientRect().width;
this._boxHeight = this._curBox.getBoundingClientRect().height;
},
/**
@ -849,6 +890,7 @@ let gHistorySwipeAnimation = {
this._container.parentNode.removeChild(this._container);
this._container = null;
this._boxWidth = -1;
this._boxHeight = -1;
},
/**
@ -876,7 +918,14 @@ let gHistorySwipeAnimation = {
* The position (in X coordinates) to move the box element to.
*/
_positionBox: function HSA__positionBox(aBox, aPosition) {
aBox.style.transform = "translateX(" + this._boxWidth * aPosition + "px)";
let transform = "";
if (this._direction == "vertical")
transform = "translateY(" + this._boxHeight * aPosition + "px)";
else
transform = "translateX(" + this._boxWidth * aPosition + "px)";
aBox.style.transform = transform;
},
/**

View File

@ -108,6 +108,11 @@ CATEGORIES = {
'short': 'Potpourri',
'long': 'Potent potables and assorted snacks.',
'priority': 10,
},
'disabled': {
'short': 'Disabled',
'long': 'These commands are unavailable for your current context, run "mach <command>" to see why.',
'priority': 0,
}
}
@ -167,8 +172,9 @@ def bootstrap(topsrcdir, mozilla_dir=None):
def populate_context(context):
context.state_dir = state_dir
context.topdir = topsrcdir
mach = mach.main.Mach(topsrcdir)
mach = mach.main.Mach(os.getcwd())
mach.populate_context_handler = populate_context
for category, meta in CATEGORIES.items():

View File

@ -1,489 +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/.
'''jarmaker.py provides a python class to package up chrome content by
processing jar.mn files.
See the documentation for jar.mn on MDC for further details on the format.
'''
import sys
import os
import os.path
import errno
import re
import logging
from time import localtime
from MozZipFile import ZipFile
from cStringIO import StringIO
from mozbuild.util import (
lock_file,
PushbackIter,
)
from Preprocessor import Preprocessor
from mozbuild.action.buildlist import addEntriesToListFile
if sys.platform == "win32":
from ctypes import windll, WinError
CreateHardLink = windll.kernel32.CreateHardLinkA
__all__ = ['JarMaker']
class ZipEntry:
'''Helper class for jar output.
This class defines a simple file-like object for a zipfile.ZipEntry
so that we can consecutively write to it and then close it.
This methods hooks into ZipFile.writestr on close().
'''
def __init__(self, name, zipfile):
self._zipfile = zipfile
self._name = name
self._inner = StringIO()
def write(self, content):
'Append the given content to this zip entry'
self._inner.write(content)
return
def close(self):
'The close method writes the content back to the zip file.'
self._zipfile.writestr(self._name, self._inner.getvalue())
def getModTime(aPath):
if not os.path.isfile(aPath):
return 0
mtime = os.stat(aPath).st_mtime
return localtime(mtime)
class JarMaker(object):
'''JarMaker reads jar.mn files and process those into jar files or
flat directories, along with chrome.manifest files.
'''
ignore = re.compile('\s*(\#.*)?$')
jarline = re.compile('(?:(?P<jarfile>[\w\d.\-\_\\\/]+).jar\:)|(?:\s*(\#.*)?)\s*$')
relsrcline = re.compile('relativesrcdir\s+(?P<relativesrcdir>.+?):')
regline = re.compile('\%\s+(.*)$')
entryre = '(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
entryline = re.compile(entryre + '(?P<output>[\w\d.\-\_\\\/\+\@]+)\s*(\((?P<locale>\%?)(?P<source>[\w\d.\-\_\\\/\@]+)\))?\s*$')
def __init__(self, outputFormat = 'flat', useJarfileManifest = True,
useChromeManifest = False):
self.outputFormat = outputFormat
self.useJarfileManifest = useJarfileManifest
self.useChromeManifest = useChromeManifest
self.pp = Preprocessor()
self.topsourcedir = None
self.sourcedirs = []
self.localedirs = None
self.l10nbase = None
self.l10nmerge = None
self.relativesrcdir = None
self.rootManifestAppId = None
def getCommandLineParser(self):
'''Get a optparse.OptionParser for jarmaker.
This OptionParser has the options for jarmaker as well as
the options for the inner PreProcessor.
'''
# HACK, we need to unescape the string variables we get,
# the perl versions didn't grok strings right
p = self.pp.getCommandLineParser(unescapeDefines = True)
p.add_option('-f', type="choice", default="jar",
choices=('jar', 'flat', 'symlink'),
help="fileformat used for output", metavar="[jar, flat, symlink]")
p.add_option('-v', action="store_true", dest="verbose",
help="verbose output")
p.add_option('-q', action="store_false", dest="verbose",
help="verbose output")
p.add_option('-e', action="store_true",
help="create chrome.manifest instead of jarfile.manifest")
p.add_option('--both-manifests', action="store_true",
dest="bothManifests",
help="create chrome.manifest and jarfile.manifest")
p.add_option('-s', type="string", action="append", default=[],
help="source directory")
p.add_option('-t', type="string",
help="top source directory")
p.add_option('-c', '--l10n-src', type="string", action="append",
help="localization directory")
p.add_option('--l10n-base', type="string", action="store",
help="base directory to be used for localization (requires relativesrcdir)")
p.add_option('--locale-mergedir', type="string", action="store",
help="base directory to be used for l10n-merge (requires l10n-base and relativesrcdir)")
p.add_option('--relativesrcdir', type="string",
help="relativesrcdir to be used for localization")
p.add_option('-j', type="string",
help="jarfile directory")
p.add_option('--root-manifest-entry-appid', type="string",
help="add an app id specific root chrome manifest entry.")
return p
def processIncludes(self, includes):
'''Process given includes with the inner PreProcessor.
Only use this for #defines, the includes shouldn't generate
content.
'''
self.pp.out = StringIO()
for inc in includes:
self.pp.do_include(inc)
includesvalue = self.pp.out.getvalue()
if includesvalue:
logging.info("WARNING: Includes produce non-empty output")
self.pp.out = None
pass
def finalizeJar(self, jarPath, chromebasepath, register,
doZip=True):
'''Helper method to write out the chrome registration entries to
jarfile.manifest or chrome.manifest, or both.
The actual file processing is done in updateManifest.
'''
# rewrite the manifest, if entries given
if not register:
return
chromeManifest = os.path.join(os.path.dirname(jarPath),
'..', 'chrome.manifest')
if self.useJarfileManifest:
self.updateManifest(jarPath + '.manifest', chromebasepath.format(''),
register)
addEntriesToListFile(chromeManifest, ['manifest chrome/{0}.manifest'
.format(os.path.basename(jarPath))])
if self.useChromeManifest:
self.updateManifest(chromeManifest, chromebasepath.format('chrome/'),
register)
# If requested, add a root chrome manifest entry (assumed to be in the parent directory
# of chromeManifest) with the application specific id. In cases where we're building
# lang packs, the root manifest must know about application sub directories.
if self.rootManifestAppId:
rootChromeManifest = os.path.join(os.path.normpath(os.path.dirname(chromeManifest)),
'..', 'chrome.manifest')
rootChromeManifest = os.path.normpath(rootChromeManifest)
chromeDir = os.path.basename(os.path.dirname(os.path.normpath(chromeManifest)))
logging.info("adding '%s' entry to root chrome manifest appid=%s" % (chromeDir, self.rootManifestAppId))
addEntriesToListFile(rootChromeManifest, ['manifest %s/chrome.manifest application=%s' % (chromeDir, self.rootManifestAppId)])
def updateManifest(self, manifestPath, chromebasepath, register):
'''updateManifest replaces the % in the chrome registration entries
with the given chrome base path, and updates the given manifest file.
'''
lock = lock_file(manifestPath + '.lck')
try:
myregister = dict.fromkeys(map(lambda s: s.replace('%', chromebasepath),
register.iterkeys()))
manifestExists = os.path.isfile(manifestPath)
mode = (manifestExists and 'r+b') or 'wb'
mf = open(manifestPath, mode)
if manifestExists:
# import previous content into hash, ignoring empty ones and comments
imf = re.compile('(#.*)?$')
for l in re.split('[\r\n]+', mf.read()):
if imf.match(l):
continue
myregister[l] = None
mf.seek(0)
for k in myregister.iterkeys():
mf.write(k + os.linesep)
mf.close()
finally:
lock = None
def makeJar(self, infile, jardir):
'''makeJar is the main entry point to JarMaker.
It takes the input file, the output directory, the source dirs and the
top source dir as argument, and optionally the l10n dirs.
'''
# making paths absolute, guess srcdir if file and add to sourcedirs
_normpath = lambda p: os.path.normpath(os.path.abspath(p))
self.topsourcedir = _normpath(self.topsourcedir)
self.sourcedirs = [_normpath(p) for p in self.sourcedirs]
if self.localedirs:
self.localedirs = [_normpath(p) for p in self.localedirs]
elif self.relativesrcdir:
self.localedirs = self.generateLocaleDirs(self.relativesrcdir)
if isinstance(infile, basestring):
logging.info("processing " + infile)
self.sourcedirs.append(_normpath(os.path.dirname(infile)))
pp = self.pp.clone()
pp.out = StringIO()
pp.do_include(infile)
lines = PushbackIter(pp.out.getvalue().splitlines())
try:
while True:
l = lines.next()
m = self.jarline.match(l)
if not m:
raise RuntimeError(l)
if m.group('jarfile') is None:
# comment
continue
self.processJarSection(m.group('jarfile'), lines, jardir)
except StopIteration:
# we read the file
pass
return
def generateLocaleDirs(self, relativesrcdir):
if os.path.basename(relativesrcdir) == 'locales':
# strip locales
l10nrelsrcdir = os.path.dirname(relativesrcdir)
else:
l10nrelsrcdir = relativesrcdir
locdirs = []
# generate locales dirs, merge, l10nbase, en-US
if self.l10nmerge:
locdirs.append(os.path.join(self.l10nmerge, l10nrelsrcdir))
if self.l10nbase:
locdirs.append(os.path.join(self.l10nbase, l10nrelsrcdir))
if self.l10nmerge or not self.l10nbase:
# add en-US if we merge, or if it's not l10n
locdirs.append(os.path.join(self.topsourcedir, relativesrcdir, 'en-US'))
return locdirs
def processJarSection(self, jarfile, lines, jardir):
'''Internal method called by makeJar to actually process a section
of a jar.mn file.
jarfile is the basename of the jarfile or the directory name for
flat output, lines is a PushbackIter of the lines of jar.mn,
the remaining options are carried over from makeJar.
'''
# chromebasepath is used for chrome registration manifests
# {0} is getting replaced with chrome/ for chrome.manifest, and with
# an empty string for jarfile.manifest
chromebasepath = '{0}' + os.path.basename(jarfile)
if self.outputFormat == 'jar':
chromebasepath = 'jar:' + chromebasepath + '.jar!'
chromebasepath += '/'
jarfile = os.path.join(jardir, jarfile)
jf = None
if self.outputFormat == 'jar':
#jar
jarfilepath = jarfile + '.jar'
try:
os.makedirs(os.path.dirname(jarfilepath))
except OSError as error:
if error.errno != errno.EEXIST:
raise
jf = ZipFile(jarfilepath, 'a', lock = True)
outHelper = self.OutputHelper_jar(jf)
else:
outHelper = getattr(self, 'OutputHelper_' + self.outputFormat)(jarfile)
register = {}
# This loop exits on either
# - the end of the jar.mn file
# - an line in the jar.mn file that's not part of a jar section
# - on an exception raised, close the jf in that case in a finally
try:
while True:
try:
l = lines.next()
except StopIteration:
# we're done with this jar.mn, and this jar section
self.finalizeJar(jarfile, chromebasepath, register)
if jf is not None:
jf.close()
# reraise the StopIteration for makeJar
raise
if self.ignore.match(l):
continue
m = self.relsrcline.match(l)
if m:
relativesrcdir = m.group('relativesrcdir')
self.localedirs = self.generateLocaleDirs(relativesrcdir)
continue
m = self.regline.match(l)
if m:
rline = m.group(1)
register[rline] = 1
continue
m = self.entryline.match(l)
if not m:
# neither an entry line nor chrome reg, this jar section is done
self.finalizeJar(jarfile, chromebasepath, register)
if jf is not None:
jf.close()
lines.pushback(l)
return
self._processEntryLine(m, outHelper, jf)
finally:
if jf is not None:
jf.close()
return
def _processEntryLine(self, m, outHelper, jf):
out = m.group('output')
src = m.group('source') or os.path.basename(out)
# pick the right sourcedir -- l10n, topsrc or src
if m.group('locale'):
src_base = self.localedirs
elif src.startswith('/'):
# path/in/jar/file_name.xul (/path/in/sourcetree/file_name.xul)
# refers to a path relative to topsourcedir, use that as base
# and strip the leading '/'
src_base = [self.topsourcedir]
src = src[1:]
else:
# use srcdirs and the objdir (current working dir) for relative paths
src_base = self.sourcedirs + [os.getcwd()]
# check if the source file exists
realsrc = None
for _srcdir in src_base:
if os.path.isfile(os.path.join(_srcdir, src)):
realsrc = os.path.join(_srcdir, src)
break
if realsrc is None:
if jf is not None:
jf.close()
raise RuntimeError('File "{0}" not found in {1}'
.format(src, ', '.join(src_base)))
if m.group('optPreprocess'):
outf = outHelper.getOutput(out)
inf = open(realsrc)
pp = self.pp.clone()
if src[-4:] == '.css':
pp.setMarker('%')
pp.out = outf
pp.do_include(inf)
pp.warnUnused(realsrc)
outf.close()
inf.close()
return
# copy or symlink if newer or overwrite
if (m.group('optOverwrite')
or (getModTime(realsrc) >
outHelper.getDestModTime(m.group('output')))):
if self.outputFormat == 'symlink':
outHelper.symlink(realsrc, out)
return
outf = outHelper.getOutput(out)
# open in binary mode, this can be images etc
inf = open(realsrc, 'rb')
outf.write(inf.read())
outf.close()
inf.close()
class OutputHelper_jar(object):
'''Provide getDestModTime and getOutput for a given jarfile.
'''
def __init__(self, jarfile):
self.jarfile = jarfile
def getDestModTime(self, aPath):
try :
info = self.jarfile.getinfo(aPath)
return info.date_time
except:
return 0
def getOutput(self, name):
return ZipEntry(name, self.jarfile)
class OutputHelper_flat(object):
'''Provide getDestModTime and getOutput for a given flat
output directory. The helper method ensureDirFor is used by
the symlink subclass.
'''
def __init__(self, basepath):
self.basepath = basepath
def getDestModTime(self, aPath):
return getModTime(os.path.join(self.basepath, aPath))
def getOutput(self, name):
out = self.ensureDirFor(name)
# remove previous link or file
try:
os.remove(out)
except OSError as e:
if e.errno != errno.ENOENT:
raise
return open(out, 'wb')
def ensureDirFor(self, name):
out = os.path.join(self.basepath, name)
outdir = os.path.dirname(out)
if not os.path.isdir(outdir):
try:
os.makedirs(outdir)
except OSError as error:
if error.errno != errno.EEXIST:
raise
return out
class OutputHelper_symlink(OutputHelper_flat):
'''Subclass of OutputHelper_flat that provides a helper for
creating a symlink including creating the parent directories.
'''
def symlink(self, src, dest):
out = self.ensureDirFor(dest)
# remove previous link or file
try:
os.remove(out)
except OSError as e:
if e.errno != errno.ENOENT:
raise
if sys.platform != "win32":
os.symlink(src, out)
else:
# On Win32, use ctypes to create a hardlink
rv = CreateHardLink(out, src, None)
if rv == 0:
raise WinError()
def main():
jm = JarMaker()
p = jm.getCommandLineParser()
(options, args) = p.parse_args()
jm.processIncludes(options.I)
jm.outputFormat = options.f
jm.sourcedirs = options.s
jm.topsourcedir = options.t
if options.e:
jm.useChromeManifest = True
jm.useJarfileManifest = False
if options.bothManifests:
jm.useChromeManifest = True
jm.useJarfileManifest = True
if options.l10n_base:
if not options.relativesrcdir:
p.error('relativesrcdir required when using l10n-base')
if options.l10n_src:
p.error('both l10n-src and l10n-base are not supported')
jm.l10nbase = options.l10n_base
jm.relativesrcdir = options.relativesrcdir
jm.l10nmerge = options.locale_mergedir
if jm.l10nmerge and not os.path.isdir(jm.l10nmerge):
logging.warning("WARNING: --locale-mergedir passed, but '%s' does not "
"exist. Ignore this message if the locale is complete.")
elif options.locale_mergedir:
p.error('l10n-base required when using locale-mergedir')
jm.localedirs = options.l10n_src
if options.root_manifest_entry_appid:
jm.rootManifestAppId = options.root_manifest_entry_appid
noise = logging.INFO
if options.verbose is not None:
noise = (options.verbose and logging.DEBUG) or logging.WARN
if sys.version_info[:2] > (2,3):
logging.basicConfig(format = "%(message)s")
else:
logging.basicConfig()
logging.getLogger().setLevel(noise)
topsrc = options.t
topsrc = os.path.normpath(os.path.abspath(topsrc))
if not args:
infile = sys.stdin
else:
infile, = args
jm.makeJar(infile, options.j)
if __name__ == "__main__":
main()

View File

@ -352,7 +352,6 @@ DEFINES += -DSTATIC_EXPORTABLE_JS_API
endif
endif
# Flags passed to JarMaker.py
MAKE_JARS_FLAGS = \
-t $(topsrcdir) \
-f $(MOZ_CHROME_FILE_FORMAT) \

View File

@ -1451,10 +1451,10 @@ endif
endif
libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome
$(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \
$(call py_action,jar_maker,\
$(QUIET) -j $(FINAL_TARGET)/chrome \
$(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \
$(JAR_MANIFEST)
$(JAR_MANIFEST))
endif
endif

View File

@ -20,6 +20,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/EventTarget.h" // for base class
#include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext
#include "mozilla/dom/DOMString.h"
// Including 'windows.h' will #define GetClassInfo to something else.
#ifdef XP_WIN
@ -1483,9 +1484,11 @@ public:
*/
uint32_t Length() const;
void GetNodeName(nsAString& aNodeName) const
void GetNodeName(mozilla::dom::DOMString& aNodeName)
{
aNodeName = NodeName();
const nsString& nodeName = NodeName();
aNodeName.SetStringBuffer(nsStringBuffer::FromString(nodeName),
nodeName.Length());
}
void GetBaseURI(nsAString& aBaseURI) const;
bool HasChildNodes() const
@ -1536,9 +1539,15 @@ public:
mNodeInfo->GetPrefix(aPrefix);
}
#endif
void GetLocalName(nsAString& aLocalName)
void GetLocalName(mozilla::dom::DOMString& aLocalName)
{
aLocalName = mNodeInfo->LocalName();
const nsString& localName = LocalName();
if (localName.IsVoid()) {
aLocalName.SetNull();
} else {
aLocalName.SetStringBuffer(nsStringBuffer::FromString(localName),
localName.Length());
}
}
// HasAttributes is defined inline in Element.h.
bool HasAttributes() const;
@ -1756,7 +1765,7 @@ ToCanonicalSupports(nsINode* aPointer)
#define NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER(...) \
NS_IMETHOD GetNodeName(nsAString& aNodeName) __VA_ARGS__ \
{ \
nsINode::GetNodeName(aNodeName); \
aNodeName = nsINode::NodeName(); \
return NS_OK; \
} \
NS_IMETHOD GetNodeValue(nsAString& aNodeValue) __VA_ARGS__ \
@ -1858,7 +1867,7 @@ ToCanonicalSupports(nsINode* aPointer)
} \
NS_IMETHOD GetLocalName(nsAString& aLocalName) __VA_ARGS__ \
{ \
nsINode::GetLocalName(aLocalName); \
aLocalName = nsINode::LocalName(); \
return NS_OK; \
} \
using nsINode::HasAttributes; \

View File

@ -282,6 +282,13 @@ public:
uint16_t ReadyState();
// request
void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
{
Open(aMethod, aUrl, true,
mozilla::dom::Optional<nsAString>(),
mozilla::dom::Optional<nsAString>(),
aRv);
}
void Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
const mozilla::dom::Optional<nsAString>& aUser,
const mozilla::dom::Optional<nsAString>& aPassword,

View File

@ -27,11 +27,15 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
is(doc.doctype.internalSubset, null, "internalSubset should be null!");
isElement(doc.documentElement, "html");
isElement(doc.documentElement.firstChild, "head");
is(doc.documentElement.firstChild.childNodes.length, 1);
isElement(doc.documentElement.firstChild.firstChild, "title");
// Doesn't always work out in WebKit.
ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
if (title !== undefined) {
is(doc.documentElement.firstChild.childNodes.length, 1);
isElement(doc.documentElement.firstChild.firstChild, "title");
// Doesn't always work out in WebKit.
ok(doc.documentElement.firstChild.firstChild.firstChild, "Need a text node.");
is(doc.documentElement.firstChild.firstChild.firstChild.data, expectedtitle);
} else {
is(doc.documentElement.firstChild.childNodes.length, 0);
}
isElement(doc.documentElement.lastChild, "body");
is(doc.documentElement.lastChild.childNodes.length, 0);
((!title || title.indexOf("\f") === -1) ? is : todo_is)
@ -41,7 +45,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
}
checkDoc("", "", "");
checkDoc(null, "null", "null");
checkDoc(undefined, "undefined", "undefined");
checkDoc(undefined, "", "");
checkDoc("foo bar baz", "foo bar baz", "foo bar baz");
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz");
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz");

View File

@ -269,6 +269,56 @@ struct DeltaValues
double deltaY;
};
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
class nsScrollbarsForWheel {
public:
static void PrepareToScrollText(nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
// Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
static void MayInactivate();
static void Inactivate();
static bool IsActive();
static void OwnWheelTransaction(bool aOwn);
protected:
static const size_t kNumberOfTargets = 4;
static const DeltaValues directions[kNumberOfTargets];
static nsWeakFrame sActiveOwner;
static nsWeakFrame sActivatedScrollTargets[kNumberOfTargets];
static bool sHadWheelStart;
static bool sOwnWheelTransaction;
/**
* These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
* to show/hide the right scrollbars.
*/
static void TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent);
static void DeactivateAllTemporarilyActivatedScrollTargets();
};
const DeltaValues nsScrollbarsForWheel::directions[kNumberOfTargets] = {
DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1), DeltaValues(0, +1)
};
nsWeakFrame nsScrollbarsForWheel::sActiveOwner = nullptr;
nsWeakFrame nsScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
nullptr, nullptr, nullptr, nullptr
};
bool nsScrollbarsForWheel::sHadWheelStart = false;
bool nsScrollbarsForWheel::sOwnWheelTransaction = false;
/******************************************************************/
/* nsMouseWheelTransaction */
/******************************************************************/
class nsMouseWheelTransaction {
public:
static nsIFrame* GetTargetFrame() { return sTargetFrame; }
@ -277,11 +327,13 @@ public:
// Be careful, UpdateTransaction may fire a DOM event, therefore, the target
// frame might be destroyed in the event handler.
static bool UpdateTransaction(WheelEvent* aEvent);
static void MayEndTransaction();
static void EndTransaction();
static void OnEvent(WidgetEvent* aEvent);
static void Shutdown();
static uint32_t GetTimeoutTime();
static void OwnScrollbars(bool aOwn);
static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
bool aAllowScrollSpeedOverride);
@ -299,12 +351,14 @@ protected:
static int32_t GetAccelerationFactor();
static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
static nsWeakFrame sTargetFrame;
static uint32_t sTime; // in milliseconds
static uint32_t sMouseMoved; // in milliseconds
static nsITimer* sTimer;
static int32_t sScrollSeriesCounter;
static bool sOwnScrollbars;
};
nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr);
@ -312,13 +366,7 @@ uint32_t nsMouseWheelTransaction::sTime = 0;
uint32_t nsMouseWheelTransaction::sMouseMoved = 0;
nsITimer* nsMouseWheelTransaction::sTimer = nullptr;
int32_t nsMouseWheelTransaction::sScrollSeriesCounter = 0;
static bool
OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
bool nsMouseWheelTransaction::sOwnScrollbars = false;
static bool
CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
@ -328,20 +376,33 @@ CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
}
static bool
CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY)
CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY)
{
MOZ_ASSERT(aScrollFrame);
NS_ASSERTION(aDeltaX || aDeltaY,
NS_ASSERTION(aDirectionX || aDirectionY,
"One of the delta values must be non-zero at least");
nsPoint scrollPt = aScrollFrame->GetScrollPosition();
nsRect scrollRange = aScrollFrame->GetScrollRange();
uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) &&
CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) ||
(aDeltaY && (directions & nsIScrollableFrame::VERTICAL) &&
CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY));
return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDirectionX)) ||
(aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDirectionY));
}
bool
nsMouseWheelTransaction::OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
{
uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
return (now - aBaseTime > aThreshold);
}
void
nsMouseWheelTransaction::OwnScrollbars(bool aOwn)
{
sOwnScrollbars = aOwn;
}
void
@ -349,6 +410,9 @@ nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL,
"Transaction must be started with a wheel event");
nsScrollbarsForWheel::OwnWheelTransaction(false);
sTargetFrame = aTargetFrame;
sScrollSeriesCounter = 0;
if (!UpdateTransaction(aEvent)) {
@ -385,6 +449,16 @@ nsMouseWheelTransaction::UpdateTransaction(WheelEvent* aEvent)
return true;
}
void
nsMouseWheelTransaction::MayEndTransaction()
{
if (!sOwnScrollbars && nsScrollbarsForWheel::IsActive()) {
nsScrollbarsForWheel::OwnWheelTransaction(true);
} else {
EndTransaction();
}
}
void
nsMouseWheelTransaction::EndTransaction()
{
@ -392,6 +466,11 @@ nsMouseWheelTransaction::EndTransaction()
sTimer->Cancel();
sTargetFrame = nullptr;
sScrollSeriesCounter = 0;
if (sOwnScrollbars) {
sOwnScrollbars = false;
nsScrollbarsForWheel::OwnWheelTransaction(false);
nsScrollbarsForWheel::Inactivate();
}
}
void
@ -415,7 +494,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
// Terminate the current mousewheel transaction if the mouse moved more
// than ignoremovedelay milliseconds ago
EndTransaction();
MayEndTransaction();
}
return;
case NS_MOUSE_MOVE:
@ -426,7 +505,7 @@ nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent));
nsIntRect r = sTargetFrame->GetScreenRectExternal();
if (!r.Contains(pt)) {
EndTransaction();
MayEndTransaction();
return;
}
@ -475,8 +554,9 @@ nsMouseWheelTransaction::OnFailToScrollTarget()
}
// The target frame might be destroyed in the event handler, at that time,
// we need to finish the current transaction
if (!sTargetFrame)
if (!sTargetFrame) {
EndTransaction();
}
}
void
@ -491,7 +571,7 @@ nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
nsIFrame* frame = sTargetFrame;
// We need to finish current transaction before DOM event firing. Because
// the next DOM event might create strange situation for us.
EndTransaction();
MayEndTransaction();
if (Preferences::GetBool("test.mousescroll", false)) {
// This event is used for automated tests, see bug 442774.
@ -625,6 +705,127 @@ nsMouseWheelTransaction::OverrideSystemScrollSpeed(WheelEvent* aEvent)
return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues;
}
/******************************************************************/
/* nsScrollbarsForWheel */
/******************************************************************/
void
nsScrollbarsForWheel::PrepareToScrollText(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
if (aEvent->message == NS_WHEEL_START) {
nsMouseWheelTransaction::OwnScrollbars(false);
if (!IsActive()) {
TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
sHadWheelStart = true;
}
} else {
DeactivateAllTemporarilyActivatedScrollTargets();
}
}
void
nsScrollbarsForWheel::SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget)
{
if (!sHadWheelStart) {
return;
}
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(aScrollTarget);
if (!scrollbarOwner) {
return;
}
sHadWheelStart = false;
sActiveOwner = do_QueryFrame(aScrollTarget);
scrollbarOwner->ScrollbarActivityStarted();
}
void
nsScrollbarsForWheel::MayInactivate()
{
if (!sOwnWheelTransaction && nsMouseWheelTransaction::GetTargetFrame()) {
nsMouseWheelTransaction::OwnScrollbars(true);
} else {
Inactivate();
}
}
void
nsScrollbarsForWheel::Inactivate()
{
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sActiveOwner);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
sActiveOwner = nullptr;
DeactivateAllTemporarilyActivatedScrollTargets();
if (sOwnWheelTransaction) {
sOwnWheelTransaction = false;
nsMouseWheelTransaction::OwnScrollbars(false);
nsMouseWheelTransaction::EndTransaction();
}
}
bool
nsScrollbarsForWheel::IsActive()
{
if (sActiveOwner) {
return true;
}
for (size_t i = 0; i < kNumberOfTargets; ++i) {
if (sActivatedScrollTargets[i]) {
return true;
}
}
return false;
}
void
nsScrollbarsForWheel::OwnWheelTransaction(bool aOwn)
{
sOwnWheelTransaction = aOwn;
}
void
nsScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
nsEventStateManager* aESM,
nsIFrame* aTargetFrame,
WheelEvent* aEvent)
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
const DeltaValues *dir = &directions[i];
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
nsIScrollableFrame* target =
aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent,
nsEventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
if (target) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(target);
if (scrollbarOwner) {
nsIFrame* targetFrame = do_QueryFrame(target);
*scrollTarget = targetFrame;
scrollbarOwner->ScrollbarActivityStarted();
}
}
}
}
void
nsScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets()
{
for (size_t i = 0; i < kNumberOfTargets; i++) {
nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
if (*scrollTarget) {
nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(*scrollTarget);
if (scrollbarOwner) {
scrollbarOwner->ScrollbarActivityStopped();
}
*scrollTarget = nullptr;
}
}
}
/******************************************************************/
/* nsEventStateManager */
/******************************************************************/
@ -977,13 +1178,20 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
case NS_WHEEL_STOP:
{
NS_ASSERTION(aEvent->mFlags.mIsTrusted,
"Untrusted wheel event shouldn't be here");
nsIContent* content = GetFocusedContent();
if (content)
if (content) {
mCurrentTargetContent = content;
}
if (aEvent->message != NS_WHEEL_WHEEL) {
break;
}
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
@ -2545,6 +2753,20 @@ nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
{
return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
aEvent, aOptions);
}
// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
// for which scrollbarowners to activate when two finger down on trackpad
// and before any actual motion
nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions)
{
if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
// If the user recently scrolled with the mousewheel, then they probably
@ -2569,14 +2791,14 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// If the event doesn't cause scroll actually, we cannot find scroll target
// because we check if the event can cause scroll actually on each found
// scrollable frame.
if (!aEvent->deltaX && !aEvent->deltaY) {
if (!aDirectionX && !aDirectionY) {
return nullptr;
}
bool checkIfScrollableX =
aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
bool checkIfScrollableY =
aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
nsIScrollableFrame* frameToScroll = nullptr;
nsIFrame* scrollFrame =
@ -2604,8 +2826,7 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
// For default action, we should climb up the tree if cannot scroll it
// by the event actually.
bool canScroll = CanScrollOn(frameToScroll,
aEvent->deltaX, aEvent->deltaY);
bool canScroll = CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
// Comboboxes need special care.
nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
if (comboBox) {
@ -3170,25 +3391,44 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
}
break;
case NS_WHEEL_STOP:
{
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
nsScrollbarsForWheel::MayInactivate();
}
break;
case NS_WHEEL_WHEEL:
case NS_WHEEL_START:
{
MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
if (*aStatus == nsEventStatus_eConsumeNoDefault) {
nsScrollbarsForWheel::Inactivate();
break;
}
WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
case WheelPrefs::ACTION_SCROLL: {
if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
break;
}
// For scrolling of default action, we should honor the mouse wheel
// transaction.
nsScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
if (aEvent->message != NS_WHEEL_WHEEL ||
(!wheelEvent->deltaX && !wheelEvent->deltaY)) {
break;
}
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
nsScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
if (!scrollTarget) {
wheelEvent->mViewPortIsOverscrolled = true;
}
wheelEvent->overflowDeltaX = wheelEvent->deltaX;
wheelEvent->overflowDeltaY = wheelEvent->deltaY;
WheelPrefs::GetInstance()->
@ -3197,6 +3437,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
DoScrollText(scrollTarget, wheelEvent);
} else {
nsMouseWheelTransaction::EndTransaction();
nsScrollbarsForWheel::Inactivate();
}
break;
}

View File

@ -46,6 +46,7 @@ class nsEventStateManager : public nsSupportsWeakReference,
public nsIObserver
{
friend class nsMouseWheelTransaction;
friend class nsScrollbarsForWheel;
public:
typedef mozilla::TimeStamp TimeStamp;
@ -557,6 +558,12 @@ protected:
mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
double aDirectionX,
double aDirectionY,
mozilla::WheelEvent* aEvent,
ComputeScrollTargetOptions aOptions);
/**
* GetScrollAmount() returns the scroll amount in app uints of one line or
* one page. If the wheel event scrolls a page, returns the page width and

View File

@ -18,10 +18,9 @@
#include "js/RootingAPI.h"
#include "mozilla/Maybe.h"
#include "nsCOMPtr.h"
#include "nsDOMString.h"
#include "nsStringBuffer.h"
#include "nsTArray.h"
#include "nsAutoPtr.h" // for nsRefPtr member variables
#include "mozilla/dom/DOMString.h"
#include "mozilla/dom/OwningNonNull.h"
class nsWrapperCache;
@ -90,133 +89,6 @@ protected:
mutable nsCOMPtr<nsISupports> mGlobalObjectRef;
};
/**
* A class for representing string return values. This can be either passed to
* callees that have an nsString or nsAString out param or passed to a callee
* that actually knows about this class and can work with it. Such a callee may
* call SetStringBuffer on this object, but only if it plans to keep holding a
* strong ref to the stringbuffer!
*
* The proper way to store a value in this class is to either to do nothing
* (which leaves this as an empty string), to call SetStringBuffer with a
* non-null stringbuffer, to call SetNull(), or to call AsAString() and set the
* value in the resulting nsString. These options are mutually exclusive!
* Don't do more than one of them.
*
* The proper way to extract a value is to check IsNull(). If not null, then
* check HasStringBuffer(). If that's true, check for a zero length, and if the
* length is nonzero call StringBuffer(). If the length is zero this is the
* empty string. If HasStringBuffer() returns false, call AsAString() and get
* the value from that.
*/
class MOZ_STACK_CLASS DOMString {
public:
DOMString()
: mStringBuffer(nullptr)
, mLength(0)
, mIsNull(false)
{}
~DOMString()
{
MOZ_ASSERT(mString.empty() || !mStringBuffer,
"Shouldn't have both present!");
}
operator nsString&()
{
return AsAString();
}
nsString& AsAString()
{
MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?");
MOZ_ASSERT(!mIsNull, "We're already set as null");
if (mString.empty()) {
mString.construct();
}
return mString.ref();
}
bool HasStringBuffer() const
{
MOZ_ASSERT(mString.empty() || !mStringBuffer,
"Shouldn't have both present!");
MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
return mString.empty();
}
// Get the stringbuffer. This can only be called if HasStringBuffer()
// returned true and StringBufferLength() is nonzero. If that's true, it will
// never return null.
nsStringBuffer* StringBuffer() const
{
MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
MOZ_ASSERT(HasStringBuffer(),
"Don't ask for the stringbuffer if we don't have it");
MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?");
MOZ_ASSERT(mStringBuffer,
"If our length is nonzero, we better have a stringbuffer.");
return mStringBuffer;
}
// Get the length of the stringbuffer. Can only be called if
// HasStringBuffer().
uint32_t StringBufferLength() const
{
MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
return mLength;
}
void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
{
MOZ_ASSERT(mString.empty(), "We already have a string?");
MOZ_ASSERT(!mIsNull, "We're already set as null");
MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
MOZ_ASSERT(aStringBuffer, "Why are we getting null?");
mStringBuffer = aStringBuffer;
mLength = aLength;
}
void SetNull()
{
MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null");
MOZ_ASSERT(mString.empty(), "Should have no string if null");
mIsNull = true;
}
bool IsNull() const
{
MOZ_ASSERT(!mStringBuffer || mString.empty(),
"How could we have a stringbuffer and a nonempty string?");
return mIsNull || (!mString.empty() && mString.ref().IsVoid());
}
void ToString(nsAString& aString)
{
if (IsNull()) {
SetDOMStringToNull(aString);
} else if (HasStringBuffer()) {
if (StringBufferLength() == 0) {
aString.Truncate();
} else {
StringBuffer()->ToString(StringBufferLength(), aString);
}
} else {
aString = AsAString();
}
}
private:
// We need to be able to act like a string as needed
Maybe<nsAutoString> mString;
// For callees that know we exist, we can be a stringbuffer/length/null-flag
// triple.
nsStringBuffer* mStringBuffer;
uint32_t mLength;
bool mIsNull;
};
// Class for representing optional arguments.
template<typename T, typename InternalType>
class Optional_base
@ -621,4 +493,4 @@ struct ParentObject {
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_BindingDeclarations_h__
#endif // mozilla_dom_BindingDeclarations_h__

View File

@ -2703,8 +2703,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# A helper function for wrapping up the template body for
# possibly-nullable objecty stuff
def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
if isNullOrUndefined:
assert type.nullable()
if isNullOrUndefined and type.nullable():
# Just ignore templateBody and set ourselves to null.
# Note that we don't have to worry about default values
# here either, since we already examined this value.
@ -3321,9 +3320,6 @@ for (uint32_t i = 0; i < length; ++i) {
"Default": "eStringify",
"EmptyString": "eEmpty",
"Null": "eNull",
# For Missing it doesn't matter what we use here, since we'll never
# call ConvertJSValueToString on undefined in that case.
"Missing": "eStringify"
}
if type.nullable():
# For nullable strings null becomes a null string.
@ -3843,11 +3839,8 @@ class CGArgumentConverter(CGThing):
"args[${index}]"
).substitute(replacer)
self.replacementVariables["mutableVal"] = self.replacementVariables["val"]
if argument.treatUndefinedAs == "Missing":
haveValueCheck = "args.hasDefined(${index})"
else:
haveValueCheck = "${index} < args.length()"
haveValueCheck = string.Template(haveValueCheck).substitute(replacer)
haveValueCheck = string.Template(
"args.hasDefined(${index})").substitute(replacer)
self.replacementVariables["haveValue"] = haveValueCheck
self.descriptorProvider = descriptorProvider
if self.argument.optional and not self.argument.defaultValue:
@ -4988,15 +4981,6 @@ class CGMethodCall(CGThing):
CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
return
# We don't handle [TreatUndefinedAs=Missing] arguments in overload
# resolution yet.
for (_, sigArgs) in signatures:
for arg in sigArgs:
if arg.treatUndefinedAs == "Missing":
raise TypeError("No support for [TreatUndefinedAs=Missing] "
"handling in overload resolution yet: %s" %
arg.location)
# Need to find the right overload
maxArgCount = method.maxArgCount
allowedArgCounts = method.allowedArgCounts
@ -5086,22 +5070,30 @@ class CGMethodCall(CGThing):
else:
failureCode = None
type = distinguishingType(signature)
# The argument at index distinguishingIndex can't possibly
# be unset here, because we've already checked that argc is
# large enough that we can examine this argument.
# The argument at index distinguishingIndex can't possibly be
# unset here, because we've already checked that argc is large
# enough that we can examine this argument. But note that we
# still want to claim that optional arguments are optional, in
# case undefined was passed in.
argIsOptional = (distinguishingArgument(signature).optional and
not distinguishingArgument(signature).defaultValue)
testCode = instantiateJSToNativeConversion(
getJSToNativeConversionInfo(type, descriptor,
failureCode=failureCode,
isDefinitelyObject=isDefinitelyObject,
isNullOrUndefined=isNullOrUndefined,
isOptional=argIsOptional,
sourceDescription=(argDesc % (distinguishingIndex + 1))),
{
"declName" : "arg%d" % distinguishingIndex,
"holderName" : ("arg%d" % distinguishingIndex) + "_holder",
"val" : distinguishingArg,
"mutableVal" : distinguishingArg,
"obj" : "obj"
})
"obj" : "obj",
"haveValue": "args.hasDefined(%d)" % distinguishingIndex
},
checkForValue=argIsOptional
)
caseBody.append(CGIndenter(testCode, indent));
# If we got this far, we know we unwrapped to the right
# C++ type, so just do the call. Start conversion with
@ -5111,24 +5103,76 @@ class CGMethodCall(CGThing):
getPerSignatureCall(signature, distinguishingIndex + 1),
indent))
# First check for null or undefined. That means looking for
def hasConditionalConversion(type):
"""
Return whether the argument conversion for this type will be
conditional on the type of incoming JS value. For example, for
interface types the conversion is conditional on the incoming
value being isObject().
For the types for which this returns false, we do not have to
output extra isUndefined() or isNullOrUndefined() cases, because
null/undefined values will just fall through into our
unconditional conversion.
"""
if type.isString() or type.isEnum():
return False
if type.isBoolean():
distinguishingTypes = (distinguishingType(s) for s in
possibleSignatures)
return any(t.isString() or t.isEnum() or t.isNumeric()
for t in distinguishingTypes)
if type.isNumeric():
distinguishingTypes = (distinguishingType(s) for s in
possibleSignatures)
return any(t.isString() or t.isEnum()
for t in distinguishingTypes)
return True
def needsNullOrUndefinedCase(type):
"""
Return true if the type needs a special isNullOrUndefined() case
"""
return ((type.nullable() and
hasConditionalConversion(type)) or
type.isDictionary())
# First check for undefined and optional distinguishing arguments
# and output a special branch for that case. Note that we don't
# use distinguishingArgument here because we actualy want to
# exclude variadic arguments. Also note that we skip this check if
# we plan to output a isNullOrUndefined() special case for this
# argument anyway, since that will subsume our isUndefined() check.
# This is safe, because there can be at most one nullable
# distinguishing argument, so if we're it we'll definitely get
# picked up by the nullable handling. Also, we can skip this check
# if the argument has an unconditional conversion later on.
undefSigs = [s for s in possibleSignatures if
distinguishingIndex < len(s[1]) and
s[1][distinguishingIndex].optional and
hasConditionalConversion(s[1][distinguishingIndex].type) and
not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)]
# Can't have multiple signatures with an optional argument at the
# same index.
assert len(undefSigs) < 2
if len(undefSigs) > 0:
caseBody.append(CGGeneric("if (%s.isUndefined()) {" %
distinguishingArg))
tryCall(undefSigs[0], 2, isNullOrUndefined=True)
caseBody.append(CGGeneric("}"))
# Next, check for null or undefined. That means looking for
# nullable arguments at the distinguishing index and outputting a
# separate branch for them. But if the nullable argument is a
# primitive, string, or enum, we don't need to do that. The reason
# separate branch for them. But if the nullable argument has an
# unconditional conversion, we don't need to do that. The reason
# for that is that at most one argument at the distinguishing index
# is nullable (since two nullable arguments are not
# distinguishable), and all the argument types other than
# primitive/string/enum end up inside isObject() checks. So if our
# nullable is a primitive/string/enum it's safe to not output the
# extra branch: we'll fall through to conversion for those types,
# which correctly handles null as needed, because isObject() will be
# false for null and undefined.
# distinguishable), and null/undefined values will always fall
# through to the unconditional conversion we have, if any, since
# they will fail whatever the conditions on the input value are for
# our other conversions.
nullOrUndefSigs = [s for s in possibleSignatures
if ((distinguishingType(s).nullable() and not
distinguishingType(s).isString() and not
distinguishingType(s).isEnum() and not
distinguishingType(s).isPrimitive()) or
distinguishingType(s).isDictionary())]
if needsNullOrUndefinedCase(distinguishingType(s))]
# Can't have multiple nullable types here
assert len(nullOrUndefSigs) < 2
if len(nullOrUndefSigs) > 0:

149
dom/bindings/DOMString.h Normal file
View File

@ -0,0 +1,149 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DOMString_h
#define mozilla_dom_DOMString_h
#include "nsStringGlue.h"
#include "nsStringBuffer.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "nsDOMString.h"
namespace mozilla {
namespace dom {
/**
* A class for representing string return values. This can be either passed to
* callees that have an nsString or nsAString out param or passed to a callee
* that actually knows about this class and can work with it. Such a callee may
* call SetStringBuffer on this object, but only if it plans to keep holding a
* strong ref to the stringbuffer!
*
* The proper way to store a value in this class is to either to do nothing
* (which leaves this as an empty string), to call SetStringBuffer with a
* non-null stringbuffer, to call SetNull(), or to call AsAString() and set the
* value in the resulting nsString. These options are mutually exclusive!
* Don't do more than one of them.
*
* The proper way to extract a value is to check IsNull(). If not null, then
* check HasStringBuffer(). If that's true, check for a zero length, and if the
* length is nonzero call StringBuffer(). If the length is zero this is the
* empty string. If HasStringBuffer() returns false, call AsAString() and get
* the value from that.
*/
class MOZ_STACK_CLASS DOMString {
public:
DOMString()
: mStringBuffer(nullptr)
, mLength(0)
, mIsNull(false)
{}
~DOMString()
{
MOZ_ASSERT(mString.empty() || !mStringBuffer,
"Shouldn't have both present!");
}
operator nsString&()
{
return AsAString();
}
nsString& AsAString()
{
MOZ_ASSERT(!mStringBuffer, "We already have a stringbuffer?");
MOZ_ASSERT(!mIsNull, "We're already set as null");
if (mString.empty()) {
mString.construct();
}
return mString.ref();
}
bool HasStringBuffer() const
{
MOZ_ASSERT(mString.empty() || !mStringBuffer,
"Shouldn't have both present!");
MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
return mString.empty();
}
// Get the stringbuffer. This can only be called if HasStringBuffer()
// returned true and StringBufferLength() is nonzero. If that's true, it will
// never return null.
nsStringBuffer* StringBuffer() const
{
MOZ_ASSERT(!mIsNull, "Caller should have checked IsNull() first");
MOZ_ASSERT(HasStringBuffer(),
"Don't ask for the stringbuffer if we don't have it");
MOZ_ASSERT(StringBufferLength() != 0, "Why are you asking for this?");
MOZ_ASSERT(mStringBuffer,
"If our length is nonzero, we better have a stringbuffer.");
return mStringBuffer;
}
// Get the length of the stringbuffer. Can only be called if
// HasStringBuffer().
uint32_t StringBufferLength() const
{
MOZ_ASSERT(HasStringBuffer(), "Don't call this if there is no stringbuffer");
return mLength;
}
void SetStringBuffer(nsStringBuffer* aStringBuffer, uint32_t aLength)
{
MOZ_ASSERT(mString.empty(), "We already have a string?");
MOZ_ASSERT(!mIsNull, "We're already set as null");
MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
MOZ_ASSERT(aStringBuffer, "Why are we getting null?");
mStringBuffer = aStringBuffer;
mLength = aLength;
}
void SetNull()
{
MOZ_ASSERT(!mStringBuffer, "Should have no stringbuffer if null");
MOZ_ASSERT(mString.empty(), "Should have no string if null");
mIsNull = true;
}
bool IsNull() const
{
MOZ_ASSERT(!mStringBuffer || mString.empty(),
"How could we have a stringbuffer and a nonempty string?");
return mIsNull || (!mString.empty() && mString.ref().IsVoid());
}
void ToString(nsAString& aString)
{
if (IsNull()) {
SetDOMStringToNull(aString);
} else if (HasStringBuffer()) {
if (StringBufferLength() == 0) {
aString.Truncate();
} else {
StringBuffer()->ToString(StringBufferLength(), aString);
}
} else {
aString = AsAString();
}
}
private:
// We need to be able to act like a string as needed
Maybe<nsAutoString> mString;
// For callees that know we exist, we can be a stringbuffer/length/null-flag
// triple.
nsStringBuffer* mStringBuffer;
uint32_t mLength;
bool mIsNull;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_DOMString_h

View File

@ -81,11 +81,6 @@ public:
return !Equals(aOtherNullable);
}
operator bool() const
{
return !mIsNull;
}
// Make it possible to use a const Nullable of an array type with other
// array types.
template<typename U>

View File

@ -19,6 +19,7 @@ EXPORTS.mozilla.dom += [
'CallbackObject.h',
'DOMJSClass.h',
'DOMJSProxyHandler.h',
'DOMString.h',
'Date.h',
'Errors.msg',
'Exceptions.h',

View File

@ -401,12 +401,7 @@ class IDLObjectWithIdentifier(IDLObject):
if isDictionaryMember:
raise WebIDLError("[TreatUndefinedAs] is not allowed for "
"dictionary members", [self.location])
if value == 'Missing':
if not isOptional:
raise WebIDLError("[TreatUndefinedAs=Missing] is only "
"allowed on optional arguments",
[self.location])
elif value == 'Null':
if value == 'Null':
if not self.type.isDOMString():
raise WebIDLError("[TreatUndefinedAs=Null] is only "
"allowed on arguments or "
@ -426,8 +421,8 @@ class IDLObjectWithIdentifier(IDLObject):
[self.location])
else:
raise WebIDLError("[TreatUndefinedAs] must take the "
"identifiers EmptyString or Null or "
"Missing", [self.location])
"identifiers EmptyString or Null",
[self.location])
self.treatUndefinedAs = value
else:
unhandledAttrs.append(attr)
@ -3143,15 +3138,12 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
def finish(self, scope):
for overload in self._overloads:
inOptionalArguments = False
variadicArgument = None
arguments = overload.arguments
for (idx, argument) in enumerate(arguments):
if argument.isComplete():
continue
argument.complete(scope)
if not argument.isComplete():
argument.complete(scope)
assert argument.type.isComplete()
if (argument.type.isDictionary() or
@ -3161,7 +3153,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
# end of the list or followed by optional arguments must be
# optional.
if (not argument.optional and
(idx == len(arguments) - 1 or arguments[idx+1].optional)):
all(arg.optional for arg in arguments[idx+1:])):
raise WebIDLError("Dictionary argument or union "
"argument containing a dictionary "
"not followed by a required argument "
@ -3179,13 +3171,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
if variadicArgument:
raise WebIDLError("Variadic argument is not last argument",
[variadicArgument.location])
# Once we see an optional argument, there can't be any non-optional
# arguments.
if inOptionalArguments and not argument.optional:
raise WebIDLError("Non-optional argument after optional "
"arguments",
[argument.location])
inOptionalArguments = argument.optional
if argument.variadic:
variadicArgument = argument
@ -3230,7 +3215,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
return [overload for overload in self._overloads if
len(overload.arguments) == argc or
(len(overload.arguments) > argc and
overload.arguments[argc].optional) or
all(arg.optional for arg in overload.arguments[argc:])) or
(len(overload.arguments) < argc and
len(overload.arguments) > 0 and
overload.arguments[-1].variadic)]
@ -4060,21 +4045,6 @@ class Parser(Tokenizer):
raise WebIDLError("stringifier must have DOMString return type",
[self.getLocation(p, 2)])
inOptionalArguments = False
variadicArgument = False
for argument in arguments:
# Only the last argument can be variadic
if variadicArgument:
raise WebIDLError("Only the last argument can be variadic",
[variadicArgument.location])
# Once we see an optional argument, there can't be any non-optional
# arguments.
if inOptionalArguments and not argument.optional:
raise WebIDLError("Cannot have a non-optional argument following an optional argument",
[argument.location])
inOptionalArguments = argument.optional
variadicArgument = argument if argument.variadic else None
# identifier might be None. This is only permitted for special methods.
if not identifier:
if not getter and not setter and not creator and \

View File

@ -171,6 +171,23 @@ def WebIDLTest(parser, harness):
harness.ok(threw, "Dictionary arg followed by optional arg must be optional")
parser = parser.reset()
threw = False
try:
parser.parse("""
dictionary A {
};
interface X {
void doFoo(A arg1, optional long arg2, long arg3);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(not threw,
"Dictionary arg followed by non-optional arg doesn't have to be optional")
parser = parser.reset()
threw = False
try:

View File

@ -11,9 +11,9 @@ def WebIDLTest(parser, harness):
except:
threw = True
harness.ok(threw,
"Should have thrown on non-optional argument following optional "
"argument.")
harness.ok(not threw,
"Should not have thrown on non-optional argument following "
"optional argument.")
parser = parser.reset()
parser.parse("""

View File

@ -11,6 +11,8 @@ def WebIDLTest(parser, harness):
void withVariadics(long... numbers);
void withVariadics(TestOverloads iface);
void withVariadics(long num, TestOverloads iface);
void optionalTest();
void optionalTest(optional long num1, long num2);
};
""")
@ -23,7 +25,7 @@ def WebIDLTest(parser, harness):
"Should be an IDLInterface")
harness.check(iface.identifier.QName(), "::TestOverloads", "Interface has the right QName")
harness.check(iface.identifier.name, "TestOverloads", "Interface has the right name")
harness.check(len(iface.members), 3, "Expect %s members" % 3)
harness.check(len(iface.members), 4, "Expect %s members" % 4)
member = iface.members[0]
harness.check(member.identifier.QName(), "::TestOverloads::basic", "Method has the right QName")
@ -48,3 +50,11 @@ def WebIDLTest(parser, harness):
harness.check(argument.identifier.QName(), "::TestOverloads::basic::arg1", "Argument has the right QName")
harness.check(argument.identifier.name, "arg1", "Argument has the right name")
harness.check(str(argument.type), "Long", "Argument has the right type")
member = iface.members[3]
harness.check(len(member.overloadsForArgCount(0)), 1,
"Only one overload for no args")
harness.check(len(member.overloadsForArgCount(1)), 0,
"No overloads for one arg")
harness.check(len(member.overloadsForArgCount(2)), 1,
"Only one overload for two args")

View File

@ -1,51 +1,62 @@
def WebIDLTest(parser, harness):
threw = False
try:
results = parser.parse("""
parser.parse("""
interface VariadicConstraints1 {
void foo(byte... arg1, byte arg2);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown.")
harness.ok(threw,
"Should have thrown on variadic argument followed by required "
"argument.")
parser = parser.reset()
threw = False
try:
results = parser.parse("""
parser.parse("""
interface VariadicConstraints2 {
void foo(byte... arg1, optional byte arg2);
};
""")
results = parser.finish();
except:
threw = True
harness.ok(threw, "Should have thrown.")
harness.ok(threw,
"Should have thrown on variadic argument followed by optional "
"argument.")
parser = parser.reset()
threw = False
try:
results = parser.parse("""
parser.parse("""
interface VariadicConstraints3 {
void foo(optional byte... arg1);
};
""")
results = parser.finish()
except:
threw = True
harness.ok(threw, "Should have thrown.")
harness.ok(threw,
"Should have thrown on variadic argument explicitly flagged as "
"optional.")
parser = parser.reset()
threw = False
try:
results = parser.parse("""
parser.parse("""
interface VariadicConstraints4 {
void foo(byte... arg1 = 0);
};
""")
results = parser.finish()
except:
threw = True

View File

@ -161,9 +161,9 @@ public:
void PassByte(int8_t);
int8_t ReceiveByte();
void PassOptionalByte(const Optional<int8_t>&);
void PassOptionalUndefinedMissingByte(const Optional<int8_t>&);
void PassOptionalByteBeforeRequired(const Optional<int8_t>&, int8_t);
void PassOptionalByteWithDefault(int8_t);
void PassOptionalUndefinedMissingByteWithDefault(int8_t);
void PassOptionalByteWithDefaultBeforeRequired(int8_t, int8_t);
void PassNullableByte(const Nullable<int8_t>&);
void PassOptionalNullableByte(const Optional< Nullable<int8_t> >&);
void PassVariadicByte(const Sequence<int8_t>&);
@ -410,9 +410,7 @@ public:
void PassString(const nsAString&);
void PassNullableString(const nsAString&);
void PassOptionalString(const Optional<nsAString>&);
void PassOptionalUndefinedMissingString(const Optional<nsAString>&);
void PassOptionalStringWithDefaultValue(const nsAString&);
void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&);
void PassOptionalNullableString(const Optional<nsAString>&);
void PassOptionalNullableStringWithDefaultValue(const nsAString&);
void PassVariadicString(const Sequence<nsString>&);
@ -631,6 +629,22 @@ public:
void Overload7(const nsCString&);
void Overload8(int32_t);
void Overload8(TestInterface&);
void Overload9(const Nullable<int32_t>&);
void Overload9(const nsAString&);
void Overload10(const Nullable<int32_t>&);
void Overload10(JSContext*, JS::Handle<JSObject*>);
void Overload11(int32_t);
void Overload11(const nsAString&);
void Overload12(int32_t);
void Overload12(const Nullable<bool>&);
void Overload13(const Nullable<int32_t>&);
void Overload13(bool);
void Overload14(const Optional<int32_t>&);
void Overload14(TestInterface&);
void Overload15(int32_t);
void Overload15(const Optional<NonNull<TestInterface> >&);
void Overload16(int32_t);
void Overload16(const Optional<TestInterface*>&);
// Variadic handling
void PassVariadicThirdArg(const nsAString&, int32_t,

View File

@ -118,9 +118,9 @@ interface TestInterface {
void passByte(byte arg);
byte receiveByte();
void passOptionalByte(optional byte arg);
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
void passOptionalByteWithDefault(optional byte arg = 0);
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
void passNullableByte(byte? arg);
void passOptionalNullableByte(optional byte? arg);
void passVariadicByte(byte... arg);
@ -365,9 +365,7 @@ interface TestInterface {
void passString(DOMString arg);
void passNullableString(DOMString? arg);
void passOptionalString(optional DOMString arg);
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
void passOptionalNullableString(optional DOMString? arg);
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
void passVariadicString(DOMString... arg);
@ -581,6 +579,22 @@ interface TestInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
void overload14(optional long arg);
void overload14(TestInterface arg);
void overload15(long arg);
void overload15(optional TestInterface arg);
void overload16(long arg);
void overload16(optional TestInterface? arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);

View File

@ -23,9 +23,9 @@ interface TestExampleInterface {
void passByte(byte arg);
byte receiveByte();
void passOptionalByte(optional byte arg);
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
void passOptionalByteWithDefault(optional byte arg = 0);
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
void passNullableByte(byte? arg);
void passOptionalNullableByte(optional byte? arg);
void passVariadicByte(byte... arg);
@ -263,9 +263,7 @@ interface TestExampleInterface {
void passString(DOMString arg);
void passNullableString(DOMString? arg);
void passOptionalString(optional DOMString arg);
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
void passOptionalNullableString(optional DOMString? arg);
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
void passVariadicString(DOMString... arg);
@ -478,6 +476,22 @@ interface TestExampleInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
void overload14(optional long arg);
void overload14(TestInterface arg);
void overload15(long arg);
void overload15(optional TestInterface arg);
void overload16(long arg);
void overload16(optional TestInterface? arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestInterface... arg3);

View File

@ -35,9 +35,9 @@ interface TestJSImplInterface {
void passByte(byte arg);
byte receiveByte();
void passOptionalByte(optional byte arg);
void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg);
void passOptionalByteBeforeRequired(optional byte arg1, byte arg2);
void passOptionalByteWithDefault(optional byte arg = 0);
void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0);
void passOptionalByteWithDefaultBeforeRequired(optional byte arg1 = 0, byte arg2);
void passNullableByte(byte? arg);
void passOptionalNullableByte(optional byte? arg);
void passVariadicByte(byte... arg);
@ -285,9 +285,7 @@ interface TestJSImplInterface {
void passString(DOMString arg);
void passNullableString(DOMString? arg);
void passOptionalString(optional DOMString arg);
void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg);
void passOptionalStringWithDefaultValue(optional DOMString arg = "abc");
void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc");
void passOptionalNullableString(optional DOMString? arg);
void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null);
void passVariadicString(DOMString... arg);
@ -506,6 +504,22 @@ interface TestJSImplInterface {
void overload7(ByteString arg);
void overload8(long arg);
void overload8(TestJSImplInterface arg);
void overload9(long? arg);
void overload9(DOMString arg);
void overload10(long? arg);
void overload10(object arg);
void overload11(long arg);
void overload11(DOMString? arg);
void overload12(long arg);
void overload12(boolean? arg);
void overload13(long? arg);
void overload13(boolean arg);
void overload14(optional long arg);
void overload14(TestInterface arg);
void overload15(long arg);
void overload15(optional TestInterface arg);
void overload16(long arg);
void overload16(optional TestInterface? arg);
// Variadic handling
void passVariadicThirdArg(DOMString arg1, long arg2, TestJSImplInterface... arg3);

View File

@ -18,17 +18,21 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
assert_equals(doc.doctype.systemId, "")
assert_equals(doc.documentElement.localName, "html")
assert_equals(doc.documentElement.firstChild.localName, "head")
assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
expectedtitle)
if (title !== undefined) {
assert_equals(doc.documentElement.firstChild.childNodes.length, 1)
assert_equals(doc.documentElement.firstChild.firstChild.localName, "title")
assert_equals(doc.documentElement.firstChild.firstChild.firstChild.data,
expectedtitle)
} else {
assert_equals(doc.documentElement.firstChild.childNodes.length, 0)
}
assert_equals(doc.documentElement.lastChild.localName, "body")
assert_equals(doc.documentElement.lastChild.childNodes.length, 0)
})
}
checkDoc("", "", "")
checkDoc(null, "null", "null")
checkDoc(undefined, "undefined", "undefined")
checkDoc(undefined, "", "")
checkDoc("foo bar baz", "foo bar baz", "foo bar baz")
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")

View File

@ -12,7 +12,7 @@ function checkDoc(title, expectedtitle, normalizedtitle) {
}
checkDoc("", "", "")
checkDoc(null, "null", "null")
checkDoc(undefined, "undefined", "undefined")
checkDoc(undefined, "", "")
checkDoc("foo bar baz", "foo bar baz", "foo bar baz")
checkDoc("foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz")
checkDoc("foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz")

View File

@ -2802,7 +2802,7 @@ QuotaManager::FindSynchronizedOp(const nsACString& aPattern,
for (uint32_t index = 0; index < mSynchronizedOps.Length(); index++) {
const nsAutoPtr<SynchronizedOp>& currentOp = mSynchronizedOps[index];
if (PatternMatchesOrigin(aPattern, currentOp->mOriginOrPattern) &&
(!currentOp->mPersistenceType ||
(currentOp->mPersistenceType.IsNull() ||
currentOp->mPersistenceType == aPersistenceType) &&
(!currentOp->mId || currentOp->mId == aId)) {
return currentOp;
@ -3067,7 +3067,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
uint32_t index;
for (index = 0; index < mSynchronizedOps.Length(); index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (!op->mPersistenceType ||
if (op->mPersistenceType.IsNull() ||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
if (op->mOriginOrPattern.IsPattern() &&
!originCollection.ContainsPattern(op->mOriginOrPattern)) {
@ -3078,7 +3078,7 @@ QuotaManager::CollectOriginsForEviction(uint64_t aMinSizeToBeFreed,
for (index = 0; index < mSynchronizedOps.Length(); index++) {
nsAutoPtr<SynchronizedOp>& op = mSynchronizedOps[index];
if (!op->mPersistenceType ||
if (op->mPersistenceType.IsNull() ||
op->mPersistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
if (op->mOriginOrPattern.IsOrigin() &&
!originCollection.ContainsOrigin(op->mOriginOrPattern)) {

View File

@ -74,7 +74,7 @@ interface CanvasRenderingContext2D {
// path API (see also CanvasPathMethods)
void beginPath();
void fill([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
void fill(optional CanvasWindingRule winding = "nonzero");
// NOT IMPLEMENTED void fill(Path path);
void stroke();
// NOT IMPLEMENTED void stroke(Path path);
@ -84,10 +84,10 @@ interface CanvasRenderingContext2D {
// NOT IMPLEMENTED boolean drawCustomFocusRing(Path path, Element element);
// NOT IMPLEMENTED void scrollPathIntoView();
// NOT IMPLEMENTED void scrollPathIntoView(Path path);
void clip([TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
void clip(optional CanvasWindingRule winding = "nonzero");
// NOT IMPLEMENTED void clip(Path path);
// NOT IMPLEMENTED void resetClip();
boolean isPointInPath(unrestricted double x, unrestricted double y, [TreatUndefinedAs=Missing] optional CanvasWindingRule winding = "nonzero");
boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
// NOT IMPLEMENTED boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
boolean isPointInStroke(double x, double y);

View File

@ -27,22 +27,22 @@ interface Notification : EventTarget {
attribute EventHandler onclose;
[Constant]
[Pure]
readonly attribute DOMString title;
[Constant]
[Pure]
readonly attribute NotificationDirection dir;
[Constant]
[Pure]
readonly attribute DOMString? lang;
[Constant]
[Pure]
readonly attribute DOMString? body;
[Constant]
readonly attribute DOMString? tag;
[Constant]
[Pure]
readonly attribute DOMString? icon;
void close();

View File

@ -28,9 +28,9 @@ interface Promise {
static Promise reject(any value);
[Creator]
Promise then([TreatUndefinedAs=Missing] optional AnyCallback fulfillCallback,
[TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
Promise then(optional AnyCallback fulfillCallback,
optional AnyCallback rejectCallback);
[Creator]
Promise catch([TreatUndefinedAs=Missing] optional AnyCallback rejectCallback);
Promise catch(optional AnyCallback rejectCallback);
};

View File

@ -71,7 +71,9 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
// request
[Throws]
void open(ByteString method, DOMString url, optional boolean async = true,
void open(ByteString method, DOMString url);
[Throws]
void open(ByteString method, DOMString url, boolean async,
optional DOMString? user, optional DOMString? password);
[Throws]
void setRequestHeader(ByteString header, ByteString value);

View File

@ -121,6 +121,11 @@ public:
return mStateData.mReadyState;
}
void Open(const nsACString& aMethod, const nsAString& aUrl, ErrorResult& aRv)
{
Open(aMethod, aUrl, true, Optional<nsAString>(),
Optional<nsAString>(), aRv);
}
void
Open(const nsACString& aMethod, const nsAString& aUrl, bool aAsync,
const Optional<nsAString>& aUser, const Optional<nsAString>& aPassword,

View File

@ -62,8 +62,7 @@ NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
{
nsCOMPtr<nsIContent>nodeAsContent = do_QueryInterface(mNode);
nsCOMPtr<nsIContent>parentAsContent = do_QueryInterface(mParent);
nsString namestr;
mNode->GetNodeName(namestr);
nsString namestr = mNode->NodeName();
char* nodename = ToNewCString(namestr);
printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n",
static_cast<void*>(this),

View File

@ -269,12 +269,12 @@ void
PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransform) const
{
if (aTransform) {
int i = 0;
size_t i = 0;
while (i < mPathData.size()) {
uint32_t pointCount = mPathData[i].header.length - 1;
aBuilder->mPathData.push_back(mPathData[i]);
i++;
for (int c = 0; c < pointCount; c++) {
for (uint32_t c = 0; c < pointCount; c++) {
cairo_path_data_t data;
Point newPoint = *aTransform * Point(mPathData[i].point.x, mPathData[i].point.y);
data.point.x = newPoint.x;
@ -284,7 +284,7 @@ PathCairo::AppendPathToBuilder(PathBuilderCairo *aBuilder, const Matrix *aTransf
}
}
} else {
for (int i = 0; i < mPathData.size(); i++) {
for (size_t i = 0; i < mPathData.size(); i++) {
aBuilder->mPathData.push_back(mPathData[i]);
}
}

View File

@ -61,12 +61,12 @@ struct InefficientNonFlatteningStringHashPolicy
#define ZERO_SIZE(gc, mSize) mSize(0),
#define COPY_OTHER_SIZE(gc, mSize) mSize(other.mSize),
#define ADD_OTHER_SIZE(gc, mSize) mSize += other.mSize;
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(gc, mSize) n += (gc == js::IsLiveGCThing) ? mSize : 0;
#define ADD_SIZE_TO_N_IF_LIVE_GC_THING(gc, mSize) n += (gc) ? mSize : 0;
// Used to annotate which size_t fields measure live GC things and which don't.
enum {
IsLiveGCThing,
NotLiveGCThing
NotLiveGCThing = false,
IsLiveGCThing = true
};
struct ZoneStatsPod

View File

@ -352,7 +352,6 @@ DEFINES += -DSTATIC_EXPORTABLE_JS_API
endif
endif
# Flags passed to JarMaker.py
MAKE_JARS_FLAGS = \
-t $(topsrcdir) \
-f $(MOZ_CHROME_FILE_FORMAT) \

View File

@ -1451,10 +1451,10 @@ endif
endif
libs realchrome:: $(CHROME_DEPS) $(FINAL_TARGET)/chrome
$(PYTHON) $(MOZILLA_DIR)/config/JarMaker.py \
$(call py_action,jar_maker,\
$(QUIET) -j $(FINAL_TARGET)/chrome \
$(MAKE_JARS_FLAGS) $(XULPPFLAGS) $(DEFINES) $(ACDEFINES) \
$(JAR_MANIFEST)
$(JAR_MANIFEST))
endif
endif

View File

@ -454,6 +454,8 @@ frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *cha
script->directlyInsideEval = true;
if (lazy->usesArgumentsAndApply())
script->usesArgumentsAndApply = true;
if (lazy->hasBeenCloned())
script->hasBeenCloned = true;
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval,
/* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true,
@ -461,6 +463,9 @@ frontend::CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *cha
if (!bce.init())
return false;
if (lazy->treatAsRunOnce())
bce.lazyRunOnceLambda = true;
return EmitFunctionScript(cx, &bce, pn->pn_body);
}

View File

@ -107,6 +107,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
hasSingletons(false),
emittingForInit(false),
emittingRunOnceLambda(false),
lazyRunOnceLambda(false),
insideEval(insideEval),
hasGlobalScope(hasGlobalScope),
emitterMode(emitterMode)
@ -2666,10 +2667,11 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
* the script ends up running multiple times via foo.caller related
* shenanigans.
*/
bool runOnce = bce->parent &&
bce->parent->emittingRunOnceLambda &&
bool runOnce =
bce->isRunOnceLambda() &&
!funbox->argumentsHasLocalBinding() &&
!funbox->isGenerator();
!funbox->isGenerator() &&
!funbox->function()->name();
if (runOnce) {
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_RUNONCE) < 0)
@ -4788,9 +4790,7 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
bce->script->compileAndGo &&
fun->isInterpreted() &&
(bce->checkSingletonContext() ||
(!bce->isInLoop() &&
bce->parent &&
bce->parent->emittingRunOnceLambda));
(!bce->isInLoop() && bce->isRunOnceLambda()));
if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
return false;
@ -4801,6 +4801,8 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
scope = bce->sc->asFunctionBox()->function();
fun->lazyScript()->setParent(scope, bce->script->sourceObject());
}
if (bce->emittingRunOnceLambda)
fun->lazyScript()->setTreatAsRunOnce();
} else {
SharedContext *outersc = bce->sc;

View File

@ -124,6 +124,12 @@ struct BytecodeEmitter
bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only
expected to run once. */
bool lazyRunOnceLambda:1; /* true while lazily emitting a script for
* a lambda which is only expected to run once. */
bool isRunOnceLambda() {
return (parent && parent->emittingRunOnceLambda) || lazyRunOnceLambda;
}
bool insideEval:1; /* True if compiling an eval-expression or a function
nested inside an eval. */

View File

@ -122,25 +122,6 @@ StoreBuffer::MonoTypeBuffer<T>::mark(JSTracer *trc)
}
}
namespace js {
namespace gc {
class AccumulateEdgesTracer : public JSTracer
{
EdgeSet *edges;
static void tracer(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) {
AccumulateEdgesTracer *trc = static_cast<AccumulateEdgesTracer *>(jstrc);
trc->edges->put(thingp);
}
public:
AccumulateEdgesTracer(JSRuntime *rt, EdgeSet *edgesArg) : edges(edgesArg) {
JS_TracerInit(this, rt, AccumulateEdgesTracer::tracer);
}
};
} /* namespace gc */
} /* namespace js */
/*** RelocatableMonoTypeBuffer ***/
template <typename T>

View File

@ -25,8 +25,6 @@
namespace js {
namespace gc {
class AccumulateEdgesTracer;
/*
* BufferableRef represents an abstract reference for use in the generational
* GC's remembered set. Entries in the store buffer that cannot be represented

View File

@ -2731,8 +2731,10 @@ CanAttachNativeSetProp(HandleObject obj, HandleId id, ConstantOrRegister val,
return SetPropertyIC::CanAttachNone;
// If the object doesn't have the property, we don't know if we can attach
// a stub to add the property until we do the VM call to add.
if (!shape)
// a stub to add the property until we do the VM call to add. If the
// property exists as a data property on the prototype, we should add
// a new, shadowing property.
if (!shape || (obj != holder && shape->hasDefaultSetter() && shape->hasSlot()))
return SetPropertyIC::MaybeCanAttachAddSlot;
if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||

View File

@ -2942,6 +2942,7 @@ LazyScript::LazyScript(JSFunction *fun, void *table, uint32_t numFreeVariables,
directlyInsideEval_(false),
usesArgumentsAndApply_(false),
hasBeenCloned_(false),
treatAsRunOnce_(false),
begin_(begin),
end_(end),
lineno_(lineno),

View File

@ -1183,7 +1183,7 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
uint32_t version_ : 8;
uint32_t numFreeVariables_ : 24;
uint32_t numInnerFunctions_ : 24;
uint32_t numInnerFunctions_ : 23;
uint32_t generatorKindBits_:2;
@ -1194,6 +1194,7 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
uint32_t directlyInsideEval_:1;
uint32_t usesArgumentsAndApply_:1;
uint32_t hasBeenCloned_:1;
uint32_t treatAsRunOnce_:1;
// Source location for the script.
uint32_t begin_;
@ -1310,6 +1311,13 @@ class LazyScript : public gc::BarrieredCell<LazyScript>
hasBeenCloned_ = true;
}
bool treatAsRunOnce() const {
return treatAsRunOnce_;
}
void setTreatAsRunOnce() {
treatAsRunOnce_ = true;
}
ScriptSource *source() const {
return sourceObject()->source();
}

View File

@ -52,7 +52,7 @@ function run_test()
// Test sync XHR sending
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
checkResults(res);
do_check_true(checkResults(res));
// negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
try {

View File

@ -77,6 +77,22 @@ nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aCont
{
}
void
nsHTMLScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsHTMLScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsresult
nsHTMLScrollFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
@ -902,6 +918,22 @@ nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContex
mInner.mClipAllDescendants = aClipAllDescendants;
}
void
nsXULScrollFrame::ScrollbarActivityStarted() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStarted();
}
}
void
nsXULScrollFrame::ScrollbarActivityStopped() const
{
if (mInner.mScrollbarActivity) {
mInner.mScrollbarActivity->ActivityStopped();
}
}
nsMargin
nsGfxScrollFrameInner::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
{

View File

@ -520,6 +520,9 @@ public:
return mInner.GetScrollbarBox(aVertical);
}
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame();
@ -810,6 +813,9 @@ public:
return mInner.GetScrollbarBox(aVertical);
}
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
// nsIScrollableFrame
virtual nsIFrame* GetScrolledFrame() const MOZ_OVERRIDE {
return mInner.GetScrolledFrame();

View File

@ -23,6 +23,13 @@ public:
* if there is no such box.
*/
virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
/**
* Show or hide scrollbars on 2 fingers touch.
* Subclasses should call their ScrollbarActivity's corresponding methods.
*/
virtual void ScrollbarActivityStarted() const = 0;
virtual void ScrollbarActivityStopped() const = 0;
};
#endif

View File

@ -8,4 +8,5 @@ MODULE = 'layout'
LIBRARY_NAME = 'gkmedias'
DIRS += ['webrtc']
if CONFIG['MOZ_WEBRTC']:
DIRS += ['webrtc']

View File

@ -4495,6 +4495,22 @@ nsTreeBodyFrame::PostScrollEvent()
}
}
void
nsTreeBodyFrame::ScrollbarActivityStarted() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStarted();
}
}
void
nsTreeBodyFrame::ScrollbarActivityStopped() const
{
if (mScrollbarActivity) {
mScrollbarActivity->ActivityStopped();
}
}
void
nsTreeBodyFrame::DetachImageListeners()
{

View File

@ -465,6 +465,9 @@ protected:
void PostScrollEvent();
void FireScrollEvent();
virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
/**
* Clear the pointer to this frame for all nsTreeImageListeners that were
* created by this frame.

55
mach
View File

@ -20,31 +20,36 @@ def load_mach(topsrcdir):
import mach_bootstrap
return mach_bootstrap.bootstrap(topsrcdir)
# Check whether the current directory is within a mach src or obj dir.
for dir_path in ancestors(os.getcwd()):
# If we find a "mozinfo.json" file, we are in the objdir.
mozinfo_path = os.path.join(dir_path, "mozinfo.json")
if os.path.isfile(mozinfo_path):
import json
info = json.load(open(mozinfo_path))
if "mozconfig" in info and "MOZCONFIG" not in os.environ:
# If the MOZCONFIG environment variable is not already set, set it
# to the value from mozinfo.json. This will tell the build system
# to look for a config file at the path in $MOZCONFIG rather than
# its default locations.
#
# Note: subprocess requires native strings in os.environ on Windows
os.environ[b"MOZCONFIG"] = str(info["mozconfig"])
def main(args):
# Check whether the current directory is within a mach src or obj dir.
for dir_path in ancestors(os.getcwd()):
# If we find a "mozinfo.json" file, we are in the objdir.
mozinfo_path = os.path.join(dir_path, 'mozinfo.json')
if os.path.isfile(mozinfo_path):
import json
info = json.load(open(mozinfo_path))
if 'mozconfig' in info and 'MOZCONFIG' not in os.environ:
# If the MOZCONFIG environment variable is not already set, set it
# to the value from mozinfo.json. This will tell the build system
# to look for a config file at the path in $MOZCONFIG rather than
# its default locations.
#
# Note: subprocess requires native strings in os.environ on Windows
os.environ[b'MOZCONFIG'] = str(info['mozconfig'])
if "topsrcdir" in info:
# Continue searching for mach_bootstrap in the source directory.
dir_path = info["topsrcdir"]
if 'topsrcdir' in info:
# Continue searching for mach_bootstrap in the source directory.
dir_path = info['topsrcdir']
# If we find the mach bootstrap module, we are in the srcdir.
mach_path = os.path.join(dir_path, "build/mach_bootstrap.py")
if os.path.isfile(mach_path):
mach = load_mach(dir_path)
sys.exit(mach.run(sys.argv[1:]))
# If we find the mach bootstrap module, we are in the srcdir.
mach_path = os.path.join(dir_path, 'build/mach_bootstrap.py')
if os.path.isfile(mach_path):
mach = load_mach(dir_path)
sys.exit(mach.run(args[1:]))
print("Could not run mach: No mach source directory found")
sys.exit(1)
print('Could not run mach: No mach source directory found.')
sys.exit(1)
if __name__ == '__main__':
main(sys.argv)

View File

@ -20,12 +20,6 @@ include $(topsrcdir)/config/makefiles/makeutils.mk
# Separate items of contention
tgt-gendir = .deps/generated_$(AB_CD)
jar-maker = \
$(firstword \
$(wildcard $(MOZILLA_DIR)/config/JarMaker.py) \
$(topsrcdir)/config/JarMaker.py \
)
GENERATED_DIRS += .deps
ifdef LOCALE_MERGEDIR
@ -130,18 +124,17 @@ search-preqs =\
$(call mkdir_deps,$(FINAL_TARGET)/chrome) \
$(search-jar) \
$(search-dir-deps) \
$(jar-maker) \
$(if $(IS_LANGUAGE_REPACK),FORCE) \
$(GLOBAL_DEPS) \
$(NULL)
.PHONY: searchplugins
searchplugins: $(search-preqs)
$(PYTHON) $(jar-maker) \
$(call py_action,jar_maker,\
$(QUIET) -j $(FINAL_TARGET)/chrome \
-s $(topsrcdir)/$(relativesrcdir)/en-US/searchplugins \
-s $(LOCALE_SRCDIR)/searchplugins \
$(MAKE_JARS_FLAGS) $(search-jar)
$(MAKE_JARS_FLAGS) $(search-jar))
$(TOUCH) $@
include $(topsrcdir)/config/rules.mk

View File

@ -7,9 +7,8 @@ from __future__ import unicode_literals
class CommandContext(object):
"""Holds run-time state so it can easily be passed to command providers."""
def __init__(self, topdir=None, cwd=None, settings=None, log_manager=None,
def __init__(self, cwd=None, settings=None, log_manager=None,
commands=None):
self.topdir = topdir
self.cwd = cwd
self.settings = settings
self.log_manager = log_manager

View File

@ -145,6 +145,7 @@ class CommandAction(argparse.Action):
# arguments corresponding to command names. This has the side-effect
# that argparse renders it nicely.
r = self._mach_registrar
disabled_commands = []
cats = [(k, v[2]) for k, v in r.categories.items()]
sorted_cats = sorted(cats, key=itemgetter(1), reverse=True)
@ -169,6 +170,9 @@ class CommandAction(argparse.Action):
is_filtered = True
break
if is_filtered:
description = handler.description
disabled_command = {'command': command, 'description': description}
disabled_commands.append(disabled_command)
continue
if group is None:
@ -179,6 +183,13 @@ class CommandAction(argparse.Action):
group.add_argument(command, help=description,
action='store_true')
if disabled_commands:
title, description, _priority = r.categories['disabled']
group = parser.add_argument_group(title, description)
for c in disabled_commands:
group.add_argument(c['command'], help=c['description'],
action='store_true')
parser.print_help()
def _handle_subcommand_help(self, parser, command):

View File

@ -289,7 +289,7 @@ To see more help for a specific command, run:
sys.stderr = orig_stderr
def _run(self, argv):
context = CommandContext(topdir=self.cwd, cwd=self.cwd,
context = CommandContext(cwd=self.cwd,
settings=self.settings, log_manager=self.log_manager,
commands=Registrar)

View File

@ -0,0 +1,15 @@
# 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 mozbuild.jar
def main(args):
return mozbuild.jar.main(args)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

View File

@ -172,11 +172,13 @@ class MozbuildObject(ProcessExecutionMixin):
# inside an objdir you probably want to perform actions on that objdir,
# not another one. This prevents accidental usage of the wrong objdir
# when the current objdir is ambiguous.
if topobjdir and config_topobjdir \
and not samepath(topobjdir, config_topobjdir) \
and not samepath(topobjdir, os.path.join(config_topobjdir, "mozilla")):
if topobjdir and config_topobjdir:
mozilla_dir = os.path.join(config_topobjdir, 'mozilla')
if not samepath(topobjdir, config_topobjdir) \
and (os.path.exists(mozilla_dir) and not samepath(topobjdir,
mozilla_dir)):
raise ObjdirMismatchException(topobjdir, config_topobjdir)
raise ObjdirMismatchException(topobjdir, config_topobjdir)
topobjdir = topobjdir or config_topobjdir
if topobjdir:

View File

@ -0,0 +1,537 @@
# 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/.
'''jarmaker.py provides a python class to package up chrome content by
processing jar.mn files.
See the documentation for jar.mn on MDC for further details on the format.
'''
import sys
import os
import errno
import re
import logging
from time import localtime
from MozZipFile import ZipFile
from cStringIO import StringIO
from mozbuild.util import (
lock_file,
PushbackIter,
)
from Preprocessor import Preprocessor
from mozbuild.action.buildlist import addEntriesToListFile
if sys.platform == 'win32':
from ctypes import windll, WinError
CreateHardLink = windll.kernel32.CreateHardLinkA
__all__ = ['JarMaker']
class ZipEntry(object):
'''Helper class for jar output.
This class defines a simple file-like object for a zipfile.ZipEntry
so that we can consecutively write to it and then close it.
This methods hooks into ZipFile.writestr on close().
'''
def __init__(self, name, zipfile):
self._zipfile = zipfile
self._name = name
self._inner = StringIO()
def write(self, content):
'''Append the given content to this zip entry'''
self._inner.write(content)
return
def close(self):
'''The close method writes the content back to the zip file.'''
self._zipfile.writestr(self._name, self._inner.getvalue())
def getModTime(aPath):
if not os.path.isfile(aPath):
return 0
mtime = os.stat(aPath).st_mtime
return localtime(mtime)
class JarMaker(object):
'''JarMaker reads jar.mn files and process those into jar files or
flat directories, along with chrome.manifest files.
'''
ignore = re.compile('\s*(\#.*)?$')
jarline = re.compile('(?:(?P<jarfile>[\w\d.\-\_\\\/]+).jar\:)|(?:\s*(\#.*)?)\s*$')
relsrcline = re.compile('relativesrcdir\s+(?P<relativesrcdir>.+?):')
regline = re.compile('\%\s+(.*)$')
entryre = '(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
entryline = re.compile(entryre
+ '(?P<output>[\w\d.\-\_\\\/\+\@]+)\s*(\((?P<locale>\%?)(?P<source>[\w\d.\-\_\\\/\@]+)\))?\s*$'
)
def __init__(self, outputFormat='flat', useJarfileManifest=True,
useChromeManifest=False):
self.outputFormat = outputFormat
self.useJarfileManifest = useJarfileManifest
self.useChromeManifest = useChromeManifest
self.pp = Preprocessor()
self.topsourcedir = None
self.sourcedirs = []
self.localedirs = None
self.l10nbase = None
self.l10nmerge = None
self.relativesrcdir = None
self.rootManifestAppId = None
def getCommandLineParser(self):
'''Get a optparse.OptionParser for jarmaker.
This OptionParser has the options for jarmaker as well as
the options for the inner PreProcessor.
'''
# HACK, we need to unescape the string variables we get,
# the perl versions didn't grok strings right
p = self.pp.getCommandLineParser(unescapeDefines=True)
p.add_option('-f', type='choice', default='jar',
choices=('jar', 'flat', 'symlink'),
help='fileformat used for output',
metavar='[jar, flat, symlink]',
)
p.add_option('-v', action='store_true', dest='verbose',
help='verbose output')
p.add_option('-q', action='store_false', dest='verbose',
help='verbose output')
p.add_option('-e', action='store_true',
help='create chrome.manifest instead of jarfile.manifest'
)
p.add_option('--both-manifests', action='store_true',
dest='bothManifests',
help='create chrome.manifest and jarfile.manifest')
p.add_option('-s', type='string', action='append', default=[],
help='source directory')
p.add_option('-t', type='string', help='top source directory')
p.add_option('-c', '--l10n-src', type='string', action='append'
, help='localization directory')
p.add_option('--l10n-base', type='string', action='store',
help='base directory to be used for localization (requires relativesrcdir)'
)
p.add_option('--locale-mergedir', type='string', action='store'
,
help='base directory to be used for l10n-merge (requires l10n-base and relativesrcdir)'
)
p.add_option('--relativesrcdir', type='string',
help='relativesrcdir to be used for localization')
p.add_option('-j', type='string', help='jarfile directory')
p.add_option('--root-manifest-entry-appid', type='string',
help='add an app id specific root chrome manifest entry.'
)
return p
def processIncludes(self, includes):
'''Process given includes with the inner PreProcessor.
Only use this for #defines, the includes shouldn't generate
content.
'''
self.pp.out = StringIO()
for inc in includes:
self.pp.do_include(inc)
includesvalue = self.pp.out.getvalue()
if includesvalue:
logging.info('WARNING: Includes produce non-empty output')
self.pp.out = None
def finalizeJar(self, jarPath, chromebasepath, register, doZip=True):
'''Helper method to write out the chrome registration entries to
jarfile.manifest or chrome.manifest, or both.
The actual file processing is done in updateManifest.
'''
# rewrite the manifest, if entries given
if not register:
return
chromeManifest = os.path.join(os.path.dirname(jarPath), '..',
'chrome.manifest')
if self.useJarfileManifest:
self.updateManifest(jarPath + '.manifest',
chromebasepath.format(''), register)
addEntriesToListFile(chromeManifest,
['manifest chrome/{0}.manifest'.format(os.path.basename(jarPath))])
if self.useChromeManifest:
self.updateManifest(chromeManifest,
chromebasepath.format('chrome/'),
register)
# If requested, add a root chrome manifest entry (assumed to be in the parent directory
# of chromeManifest) with the application specific id. In cases where we're building
# lang packs, the root manifest must know about application sub directories.
if self.rootManifestAppId:
rootChromeManifest = \
os.path.join(os.path.normpath(os.path.dirname(chromeManifest)),
'..', 'chrome.manifest')
rootChromeManifest = os.path.normpath(rootChromeManifest)
chromeDir = \
os.path.basename(os.path.dirname(os.path.normpath(chromeManifest)))
logging.info("adding '%s' entry to root chrome manifest appid=%s"
% (chromeDir, self.rootManifestAppId))
addEntriesToListFile(rootChromeManifest,
['manifest %s/chrome.manifest application=%s'
% (chromeDir,
self.rootManifestAppId)])
def updateManifest(self, manifestPath, chromebasepath, register):
'''updateManifest replaces the % in the chrome registration entries
with the given chrome base path, and updates the given manifest file.
'''
lock = lock_file(manifestPath + '.lck')
try:
myregister = dict.fromkeys(map(lambda s: s.replace('%',
chromebasepath), register.iterkeys()))
manifestExists = os.path.isfile(manifestPath)
mode = manifestExists and 'r+b' or 'wb'
mf = open(manifestPath, mode)
if manifestExists:
# import previous content into hash, ignoring empty ones and comments
imf = re.compile('(#.*)?$')
for l in re.split('[\r\n]+', mf.read()):
if imf.match(l):
continue
myregister[l] = None
mf.seek(0)
for k in myregister.iterkeys():
mf.write(k + os.linesep)
mf.close()
finally:
lock = None
def makeJar(self, infile, jardir):
'''makeJar is the main entry point to JarMaker.
It takes the input file, the output directory, the source dirs and the
top source dir as argument, and optionally the l10n dirs.
'''
# making paths absolute, guess srcdir if file and add to sourcedirs
_normpath = lambda p: os.path.normpath(os.path.abspath(p))
self.topsourcedir = _normpath(self.topsourcedir)
self.sourcedirs = [_normpath(p) for p in self.sourcedirs]
if self.localedirs:
self.localedirs = [_normpath(p) for p in self.localedirs]
elif self.relativesrcdir:
self.localedirs = \
self.generateLocaleDirs(self.relativesrcdir)
if isinstance(infile, basestring):
logging.info('processing ' + infile)
self.sourcedirs.append(_normpath(os.path.dirname(infile)))
pp = self.pp.clone()
pp.out = StringIO()
pp.do_include(infile)
lines = PushbackIter(pp.out.getvalue().splitlines())
try:
while True:
l = lines.next()
m = self.jarline.match(l)
if not m:
raise RuntimeError(l)
if m.group('jarfile') is None:
# comment
continue
self.processJarSection(m.group('jarfile'), lines,
jardir)
except StopIteration:
# we read the file
pass
return
def generateLocaleDirs(self, relativesrcdir):
if os.path.basename(relativesrcdir) == 'locales':
# strip locales
l10nrelsrcdir = os.path.dirname(relativesrcdir)
else:
l10nrelsrcdir = relativesrcdir
locdirs = []
# generate locales dirs, merge, l10nbase, en-US
if self.l10nmerge:
locdirs.append(os.path.join(self.l10nmerge, l10nrelsrcdir))
if self.l10nbase:
locdirs.append(os.path.join(self.l10nbase, l10nrelsrcdir))
if self.l10nmerge or not self.l10nbase:
# add en-US if we merge, or if it's not l10n
locdirs.append(os.path.join(self.topsourcedir,
relativesrcdir, 'en-US'))
return locdirs
def processJarSection(self, jarfile, lines, jardir):
'''Internal method called by makeJar to actually process a section
of a jar.mn file.
jarfile is the basename of the jarfile or the directory name for
flat output, lines is a PushbackIter of the lines of jar.mn,
the remaining options are carried over from makeJar.
'''
# chromebasepath is used for chrome registration manifests
# {0} is getting replaced with chrome/ for chrome.manifest, and with
# an empty string for jarfile.manifest
chromebasepath = '{0}' + os.path.basename(jarfile)
if self.outputFormat == 'jar':
chromebasepath = 'jar:' + chromebasepath + '.jar!'
chromebasepath += '/'
jarfile = os.path.join(jardir, jarfile)
jf = None
if self.outputFormat == 'jar':
# jar
jarfilepath = jarfile + '.jar'
try:
os.makedirs(os.path.dirname(jarfilepath))
except OSError, error:
if error.errno != errno.EEXIST:
raise
jf = ZipFile(jarfilepath, 'a', lock=True)
outHelper = self.OutputHelper_jar(jf)
else:
outHelper = getattr(self, 'OutputHelper_'
+ self.outputFormat)(jarfile)
register = {}
# This loop exits on either
# - the end of the jar.mn file
# - an line in the jar.mn file that's not part of a jar section
# - on an exception raised, close the jf in that case in a finally
try:
while True:
try:
l = lines.next()
except StopIteration:
# we're done with this jar.mn, and this jar section
self.finalizeJar(jarfile, chromebasepath, register)
if jf is not None:
jf.close()
# reraise the StopIteration for makeJar
raise
if self.ignore.match(l):
continue
m = self.relsrcline.match(l)
if m:
relativesrcdir = m.group('relativesrcdir')
self.localedirs = \
self.generateLocaleDirs(relativesrcdir)
continue
m = self.regline.match(l)
if m:
rline = m.group(1)
register[rline] = 1
continue
m = self.entryline.match(l)
if not m:
# neither an entry line nor chrome reg, this jar section is done
self.finalizeJar(jarfile, chromebasepath, register)
if jf is not None:
jf.close()
lines.pushback(l)
return
self._processEntryLine(m, outHelper, jf)
finally:
if jf is not None:
jf.close()
return
def _processEntryLine(self, m, outHelper, jf):
out = m.group('output')
src = m.group('source') or os.path.basename(out)
# pick the right sourcedir -- l10n, topsrc or src
if m.group('locale'):
src_base = self.localedirs
elif src.startswith('/'):
# path/in/jar/file_name.xul (/path/in/sourcetree/file_name.xul)
# refers to a path relative to topsourcedir, use that as base
# and strip the leading '/'
src_base = [self.topsourcedir]
src = src[1:]
else:
# use srcdirs and the objdir (current working dir) for relative paths
src_base = self.sourcedirs + [os.getcwd()]
# check if the source file exists
realsrc = None
for _srcdir in src_base:
if os.path.isfile(os.path.join(_srcdir, src)):
realsrc = os.path.join(_srcdir, src)
break
if realsrc is None:
if jf is not None:
jf.close()
raise RuntimeError('File "{0}" not found in {1}'.format(src,
', '.join(src_base)))
if m.group('optPreprocess'):
outf = outHelper.getOutput(out)
inf = open(realsrc)
pp = self.pp.clone()
if src[-4:] == '.css':
pp.setMarker('%')
pp.out = outf
pp.do_include(inf)
pp.warnUnused(realsrc)
outf.close()
inf.close()
return
# copy or symlink if newer or overwrite
if m.group('optOverwrite') or getModTime(realsrc) \
> outHelper.getDestModTime(m.group('output')):
if self.outputFormat == 'symlink':
outHelper.symlink(realsrc, out)
return
outf = outHelper.getOutput(out)
# open in binary mode, this can be images etc
inf = open(realsrc, 'rb')
outf.write(inf.read())
outf.close()
inf.close()
class OutputHelper_jar(object):
'''Provide getDestModTime and getOutput for a given jarfile.'''
def __init__(self, jarfile):
self.jarfile = jarfile
def getDestModTime(self, aPath):
try:
info = self.jarfile.getinfo(aPath)
return info.date_time
except:
return 0
def getOutput(self, name):
return ZipEntry(name, self.jarfile)
class OutputHelper_flat(object):
'''Provide getDestModTime and getOutput for a given flat
output directory. The helper method ensureDirFor is used by
the symlink subclass.
'''
def __init__(self, basepath):
self.basepath = basepath
def getDestModTime(self, aPath):
return getModTime(os.path.join(self.basepath, aPath))
def getOutput(self, name):
out = self.ensureDirFor(name)
# remove previous link or file
try:
os.remove(out)
except OSError, e:
if e.errno != errno.ENOENT:
raise
return open(out, 'wb')
def ensureDirFor(self, name):
out = os.path.join(self.basepath, name)
outdir = os.path.dirname(out)
if not os.path.isdir(outdir):
try:
os.makedirs(outdir)
except OSError, error:
if error.errno != errno.EEXIST:
raise
return out
class OutputHelper_symlink(OutputHelper_flat):
'''Subclass of OutputHelper_flat that provides a helper for
creating a symlink including creating the parent directories.
'''
def symlink(self, src, dest):
out = self.ensureDirFor(dest)
# remove previous link or file
try:
os.remove(out)
except OSError, e:
if e.errno != errno.ENOENT:
raise
if sys.platform != 'win32':
os.symlink(src, out)
else:
# On Win32, use ctypes to create a hardlink
rv = CreateHardLink(out, src, None)
if rv == 0:
raise WinError()
def main(args=None):
args = args or sys.argv
jm = JarMaker()
p = jm.getCommandLineParser()
(options, args) = p.parse_args(args)
jm.processIncludes(options.I)
jm.outputFormat = options.f
jm.sourcedirs = options.s
jm.topsourcedir = options.t
if options.e:
jm.useChromeManifest = True
jm.useJarfileManifest = False
if options.bothManifests:
jm.useChromeManifest = True
jm.useJarfileManifest = True
if options.l10n_base:
if not options.relativesrcdir:
p.error('relativesrcdir required when using l10n-base')
if options.l10n_src:
p.error('both l10n-src and l10n-base are not supported')
jm.l10nbase = options.l10n_base
jm.relativesrcdir = options.relativesrcdir
jm.l10nmerge = options.locale_mergedir
if jm.l10nmerge and not os.path.isdir(jm.l10nmerge):
logging.warning("WARNING: --locale-mergedir passed, but '%s' does not exist. Ignore this message if the locale is complete."
)
elif options.locale_mergedir:
p.error('l10n-base required when using locale-mergedir')
jm.localedirs = options.l10n_src
if options.root_manifest_entry_appid:
jm.rootManifestAppId = options.root_manifest_entry_appid
noise = logging.INFO
if options.verbose is not None:
noise = options.verbose and logging.DEBUG or logging.WARN
if sys.version_info[:2] > (2, 3):
logging.basicConfig(format='%(message)s')
else:
logging.basicConfig()
logging.getLogger().setLevel(noise)
topsrc = options.t
topsrc = os.path.normpath(os.path.abspath(topsrc))
if not args:
infile = sys.stdin
else:
(infile, ) = args
jm.makeJar(infile, options.j)

View File

@ -23,6 +23,7 @@ from mozbuild.base import (
MozbuildObject,
MozconfigFindException,
MozconfigLoadException,
ObjdirMismatchException,
)
@ -834,10 +835,7 @@ class Makefiles(MachCommandBase):
yield os.path.join(root, f)
@CommandProvider
class MachDebug(object):
def __init__(self, context):
self.context = context
class MachDebug(MachCommandBase):
@Command('environment', category='build-dev',
description='Show info about the mach and build environment.')
@CommandArgument('--verbose', '-v', action='store_true',
@ -847,13 +845,22 @@ class MachDebug(object):
print('platform:\n\t%s' % platform.platform())
print('python version:\n\t%s' % sys.version)
print('python prefix:\n\t%s' % sys.prefix)
print('mach cwd:\n\t%s' % self.context.cwd)
print('mach cwd:\n\t%s' % self._mach_context.cwd)
print('os cwd:\n\t%s' % os.getcwd())
print('mach directory:\n\t%s' % self.context.topdir)
print('state directory:\n\t%s' % self.context.state_dir)
print('mach directory:\n\t%s' % self._mach_context.topdir)
print('state directory:\n\t%s' % self._mach_context.state_dir)
mb = MozbuildObject(self.context.topdir, self.context.settings,
self.context.log_manager)
try:
mb = MozbuildObject.from_environment(cwd=self._mach_context.cwd)
except ObjdirMismatchException as e:
print('Ambiguous object directory detected. We detected that '
'both %s and %s could be object directories. This is '
'typically caused by having a mozconfig pointing to a '
'different object directory from the current working '
'directory. To solve this problem, ensure you do not have a '
'default mozconfig in searched paths.' % (e.objdir1,
e.objdir2))
return 1
mozconfig = None

View File

@ -200,7 +200,7 @@ class TestMozbuildObject(unittest.TestCase):
context = MockMachContext()
context.cwd = topobjdir
context.topdir = topobjdir
context.topdir = topsrcdir
context.settings = None
context.log_manager = None

View File

@ -1,3 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import print_function
import unittest
@ -8,7 +12,9 @@ from shutil import rmtree, copy2
from StringIO import StringIO
from zipfile import ZipFile
import mozunit
from JarMaker import JarMaker
from mozbuild.jar import JarMaker
if sys.platform == "win32":
import ctypes

View File

@ -7,7 +7,6 @@ ifneq (android,$(MOZ_WIDGET_TOOLKIT))
MOCHITEST_FILES = \
test_webapps_actor.html \
debugger-protocol-helper.js \
data/ \
redirect.sjs \
$(NULL)

View File

@ -429,6 +429,8 @@ enum nsEventStructType
#define NS_WHEEL_EVENT_START 5400
#define NS_WHEEL_WHEEL (NS_WHEEL_EVENT_START)
#define NS_WHEEL_START (NS_WHEEL_EVENT_START + 1)
#define NS_WHEEL_STOP (NS_WHEEL_EVENT_START + 2)
//System time is changed
#define NS_MOZ_TIME_CHANGE_EVENT 5500

View File

@ -318,7 +318,8 @@ public:
deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL),
customizedByUserPrefs(false), isMomentum(false), isPixelOnlyDevice(false),
lineOrPageDeltaX(0), lineOrPageDeltaY(0), scrollType(SCROLL_DEFAULT),
overflowDeltaX(0.0), overflowDeltaY(0.0)
overflowDeltaX(0.0), overflowDeltaY(0.0),
mViewPortIsOverscrolled(false)
{
}
@ -399,6 +400,12 @@ public:
double overflowDeltaX;
double overflowDeltaY;
// Whether or not the parent of the currently overscrolled frame is the
// ViewPort. This is false in situations when an element on the page is being
// overscrolled (such as a text field), but true when the 'page' is being
// overscrolled.
bool mViewPortIsOverscrolled;
void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets)
{
AssignMouseEventBaseData(aEvent, aCopyTargets);
@ -415,6 +422,7 @@ public:
scrollType = aEvent.scrollType;
overflowDeltaX = aEvent.overflowDeltaX;
overflowDeltaY = aEvent.overflowDeltaY;
mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
}
};

View File

@ -205,6 +205,12 @@ typedef NSInteger NSEventGestureAxis;
#endif // #ifdef __LP64__
#endif // #if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
#if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
enum {
NSEventPhaseMayBegin = 0x1 << 5
};
#endif // #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
// Undocumented scrollPhase flag that lets us discern between real scrolls and
// automatically firing momentum scroll events.
@interface NSEvent (ScrollPhase)
@ -252,6 +258,11 @@ typedef NSInteger NSEventGestureAxis;
BOOL mPendingFullDisplay;
BOOL mPendingDisplay;
// WheelStart/Stop events should always come in pairs. This BOOL records the
// last received event so that, when we receive one of the events, we make sure
// to send its pair event first, in case we didn't yet for any reason.
BOOL mExpectingWheelStop;
// Holds our drag service across multiple drag calls. The reference to the
// service is obtained when the mouse enters the view and is released when
// the mouse exits or there is a drop. This prevents us from having to
@ -290,6 +301,7 @@ typedef NSInteger NSEventGestureAxis;
#ifdef __LP64__
// Support for fluid swipe tracking.
BOOL* mCancelSwipeAnimation;
uint32_t mCurrentSwipeDir;
#endif
// Whether this uses off-main-thread compositing.
@ -354,13 +366,17 @@ typedef NSInteger NSEventGestureAxis;
- (void)rotateWithEvent:(NSEvent *)anEvent;
- (void)endGestureWithEvent:(NSEvent *)anEvent;
- (void)scrollWheel:(NSEvent *)anEvent;
// Helper function for Lion smart magnify events
+ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent;
// Support for fluid swipe tracking.
#ifdef __LP64__
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(double)overflow;
scrollOverflowX:(double)anOverflowX
scrollOverflowY:(double)anOverflowY
viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled;
#endif
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;

View File

@ -140,6 +140,8 @@ uint32_t nsChildView::sLastInputEventCount = 0;
- (void)forceRefreshOpenGL;
// set up a gecko mouse event based on a cocoa mouse event
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent;
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent;
@ -2777,6 +2779,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
#endif
mPendingDisplay = NO;
mBlockedLastMouseDown = NO;
mExpectingWheelStop = NO;
mLastMouseDownEvent = nil;
mClickThroughMouseDownEvent = nil;
@ -2796,6 +2799,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
#ifdef __LP64__
mCancelSwipeAnimation = nil;
mCurrentSwipeDir = 0;
#endif
mTopLeftCornerMask = NULL;
@ -4093,17 +4097,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
delta:0.0];
}
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
// to only invoke this support on a horizontal two-finger gesture that really
// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful
// to only invoke this support on a two-finger gesture that really
// is a swipe (and not a scroll) -- in other words, the app is responsible
// for deciding which is which. But once the decision is made, the OS tracks
// for deciding which is which. But once the decision is made, the OS tracks
// the swipe until it has finished, and decides whether or not it succeeded.
// A swipe has the same functionality as the Back and Forward buttons. For
// now swipe animation is unsupported (e.g. no bounces). This method is
// partly based on Apple sample code available at
// http://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html
// A horizontal swipe has the same functionality as the Back and Forward
// buttons.
// This method is partly based on Apple sample code available at
// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html
// (under Fluid Swipe Tracking API).
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(double)overflow
scrollOverflowX:(double)anOverflowX
scrollOverflowY:(double)anOverflowY
viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled
{
if (!nsCocoaFeatures::OnLionOrLater()) {
return;
@ -4118,6 +4125,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
return;
}
// We should only track scroll events as swipe if the viewport is being
// overscrolled.
if (!aViewPortIsOverscrolled) {
return;
}
// Verify that this is a scroll wheel event with proper phase to be tracked
// by the OS.
if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) {
@ -4125,12 +4138,10 @@ NSEvent* gLastDragMouseDownEvent = nil;
}
// Only initiate tracking if the user has tried to scroll past the edge of
// the current page (as indicated by 'overflow' being non-zero). Gecko only
// sets WidgetMouseScrollEvent.scrollOverflow when it's processing
// NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
// WidgetMouseScrollEvent.scrollOverflow only indicates left or right overflow
// for horizontal NS_MOUSE_PIXEL_SCROLL events.
if (!overflow) {
// the current page (as indicated by 'anOverflowX' or 'anOverflowY' being
// non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's
// processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events).
if (anOverflowX == 0.0 && anOverflowY == 0.0) {
return;
}
@ -4139,18 +4150,20 @@ NSEvent* gLastDragMouseDownEvent = nil;
deltaX = [anEvent scrollingDeltaX];
deltaY = [anEvent scrollingDeltaY];
} else {
deltaX = [anEvent deltaX];
deltaY = [anEvent deltaY];
return;
}
uint32_t vDirs = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN |
(uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
uint32_t direction = 0;
// Only initiate horizontal tracking for events whose horizontal element is
// at least eight times larger than its vertical element. This minimizes
// performance problems with vertical scrolls (by minimizing the possibility
// that they'll be misinterpreted as horizontal swipes), while still
// tolerating a small vertical element to a true horizontal swipe. The number
// '8' was arrived at by trial and error.
if (overflow != 0.0 && deltaX != 0.0 &&
if (anOverflowX != 0.0 && deltaX != 0.0 &&
fabsf(deltaX) > fabsf(deltaY) * 8) {
// Only initiate horizontal tracking for gestures that have just begun --
// otherwise a scroll to one side of the page can have a swipe tacked on
@ -4164,10 +4177,35 @@ NSEvent* gLastDragMouseDownEvent = nil;
} else {
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT;
}
}
// Only initiate vertical tracking for events whose vertical element is
// at least two times larger than its horizontal element. This minimizes
// performance problems. The number '2' was arrived at by trial and error.
else if (anOverflowY != 0.0 && deltaY != 0.0 &&
fabsf(deltaY) > fabsf(deltaX) * 2) {
if (deltaY < 0.0) {
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN;
} else {
direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP;
}
if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) {
// If a swipe is currently being tracked kill it -- it's been interrupted
// by another gesture event.
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
*mCancelSwipeAnimation = YES;
mCancelSwipeAnimation = nil;
[self sendSwipeEndEvent:anEvent allowedDirections:0];
}
return;
}
} else {
return;
}
// Track the direction we're going in.
mCurrentSwipeDir = direction;
// If a swipe is currently being tracked kill it -- it's been interrupted
// by another gesture event.
if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) {
@ -4189,8 +4227,14 @@ NSEvent* gLastDragMouseDownEvent = nil;
return;
}
double min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? -1 : 0;
double max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1 : 0;
CGFloat min = 0.0;
CGFloat max = 0.0;
if (!(direction & vDirs)) {
min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ?
-1.0 : 0.0;
max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ?
1.0 : 0.0;
}
__block BOOL animationCanceled = NO;
__block BOOL geckoSwipeEventSent = NO;
@ -4228,13 +4272,15 @@ NSEvent* gLastDragMouseDownEvent = nil;
if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) {
*stop = YES;
animationCanceled = YES;
if (gestureAmount == 0.0) {
if (gestureAmount == 0.0 ||
((direction & vDirs) && (direction != mCurrentSwipeDir))) {
if (mCancelSwipeAnimation)
*mCancelSwipeAnimation = YES;
mCancelSwipeAnimation = nil;
[self sendSwipeEndEvent:anEvent
allowedDirections:allowedDirectionsCopy];
}
mCurrentSwipeDir = 0;
return;
}
@ -4268,6 +4314,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
if (isComplete) {
[self sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy];
mCurrentSwipeDir = 0;
mCancelSwipeAnimation = nil;
}
}];
@ -4708,6 +4755,22 @@ static int32_t RoundUp(double aDouble)
static_cast<int32_t>(ceil(aDouble));
}
- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent
{
WidgetWheelEvent wheelEvent(true, msg, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
mExpectingWheelStop = (msg == NS_WHEEL_START);
mGeckoChild->DispatchWindowEvent(wheelEvent);
}
- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent
{
if (mExpectingWheelStop == condition) {
[self sendWheelStartOrStop:first forEvent:theEvent];
}
[self sendWheelStartOrStop:second forEvent:theEvent];
}
- (void)scrollWheel:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -4724,25 +4787,23 @@ static int32_t RoundUp(double aDouble)
return;
}
WheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
[self convertCocoaMouseEvent:theEvent toGeckoEvent:&wheelEvent];
wheelEvent.deltaMode =
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
if (nsCocoaFeatures::OnLionOrLater()) {
NSEventPhase phase = [theEvent phase];
// Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad.
if (phase & NSEventPhaseMayBegin) {
[self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent];
return;
}
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
// assertion and an Objective-C NSInternalInconsistencyException if the
// underlying "Carbon" event doesn't contain pixel scrolling information.
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [theEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
wheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) {
[self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent];
return;
}
}
WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild);
[self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent];
wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]);
wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]);
@ -4773,25 +4834,36 @@ static int32_t RoundUp(double aDouble)
return;
}
wheelEvent.isMomentum = nsCocoaUtils::IsMomentumScrollEvent(theEvent);
NPCocoaEvent cocoaEvent;
ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent,
NPCocoaEventScrollWheel,
&cocoaEvent);
mGeckoChild->DispatchWindowEvent(wheelEvent);
if (!mGeckoChild) {
return;
#ifdef __LP64__
// Only dispatch this event if we're not currently tracking a scroll event as
// swipe.
if (!mCancelSwipeAnimation || *mCancelSwipeAnimation == YES) {
#endif // #ifdef __LP64__
mGeckoChild->DispatchWindowEvent(wheelEvent);
if (!mGeckoChild) {
return;
}
#ifdef __LP64__
} else {
// Manually set these members here since we didn't dispatch the event.
wheelEvent.overflowDeltaX = wheelEvent.deltaX;
wheelEvent.overflowDeltaY = wheelEvent.deltaY;
wheelEvent.mViewPortIsOverscrolled = true;
}
#ifdef __LP64__
// overflowDeltaX tells us when the user has tried to scroll past the edge
// of a page to the left or the right (in those cases it's non-zero).
if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
wheelEvent.deltaX != 0.0) {
// overflowDeltaX and overflowDeltaY tell us when the user has tried to
// scroll past the edge of a page (in those cases it's non-zero).
if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) &&
(wheelEvent.deltaX != 0.0 || wheelEvent.deltaY != 0.0)) {
[self maybeTrackScrollEventAsSwipe:theEvent
scrollOverflow:wheelEvent.overflowDeltaX];
scrollOverflowX:wheelEvent.overflowDeltaX
scrollOverflowY:wheelEvent.overflowDeltaY
viewPortIsOverscrolled:wheelEvent.mViewPortIsOverscrolled];
}
#endif // #ifdef __LP64__
@ -4850,6 +4922,29 @@ static int32_t RoundUp(double aDouble)
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetWheelEvent*)outWheelEvent
{
[self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent];
outWheelEvent->deltaMode =
Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ?
nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE;
// Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa
// assertion and an Objective-C NSInternalInconsistencyException if the
// underlying "Carbon" event doesn't contain pixel scrolling information.
// For these events, carbonEventKind is kEventMouseWheelMoved instead of
// kEventMouseScroll.
if (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
EventRef theCarbonEvent = [aMouseEvent _eventRef];
UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0;
if (carbonEventKind != kEventMouseScroll) {
outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
}
}
outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent);
}
- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent
toGeckoEvent:(WidgetInputEvent*)outGeckoEvent
{

View File

@ -290,10 +290,7 @@ nsToolkit* nsToolkit::GetToolkit()
// Since the Method type becomes an opaque type as of Objective-C 2.0, we'll
// have to switch to using accessor methods like method_exchangeImplementations()
// when we build 64-bit binaries that use Objective-C 2.0 (on and for Leopard
// and above). But these accessor methods aren't available in Objective-C 1
// (or on Tiger). So we need to access Method's members directly for (Tiger-
// capable) binaries (32-bit or 64-bit) that use Objective-C 1 (as long as we
// keep supporting Tiger).
// and above).
//
// Be aware that, if aClass doesn't have an orgMethod selector but one of its
// superclasses does, the method substitution will (in effect) take place in
@ -321,13 +318,7 @@ nsresult nsToolkit::SwizzleMethods(Class aClass, SEL orgMethod, SEL posedMethod,
if (!original || !posed)
return NS_ERROR_FAILURE;
#ifdef __LP64__
method_exchangeImplementations(original, posed);
#else
IMP aMethodImp = original->method_imp;
original->method_imp = posed->method_imp;
posed->method_imp = aMethodImp;
#endif
return NS_OK;